@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.
Files changed (98) hide show
  1. package/dist/vuetify.js +214 -84
  2. package/dist/vuetify.js.map +1 -1
  3. package/dist/vuetify.min.css +1 -1
  4. package/dist/vuetify.min.js +2 -2
  5. package/es5/components/VOverlay/VOverlay.js +2 -3
  6. package/es5/components/VOverlay/VOverlay.js.map +1 -1
  7. package/es5/components/VProgressCircular/VProgressCircular.js +5 -3
  8. package/es5/components/VProgressCircular/VProgressCircular.js.map +1 -1
  9. package/es5/components/VProgressLinear/VProgressLinear.js +41 -19
  10. package/es5/components/VProgressLinear/VProgressLinear.js.map +1 -1
  11. package/es5/components/VTabs/VTabs.js +1 -1
  12. package/es5/components/VTabs/VTabs.js.map +1 -1
  13. package/es5/components/VTabs/VTabsBar.js.map +1 -1
  14. package/es5/components/VVirtualScroll/VVirtualScroll.js +15 -16
  15. package/es5/components/VVirtualScroll/VVirtualScroll.js.map +1 -1
  16. package/es5/components/VWindow/VWindow.js +13 -5
  17. package/es5/components/VWindow/VWindow.js.map +1 -1
  18. package/es5/components/VWindow/VWindowItem.js +9 -5
  19. package/es5/components/VWindow/VWindowItem.js.map +1 -1
  20. package/es5/framework.js +1 -1
  21. package/es5/install.js +10 -33
  22. package/es5/install.js.map +1 -1
  23. package/es5/mixins/detachable/index.js +2 -3
  24. package/es5/mixins/detachable/index.js.map +1 -1
  25. package/es5/mixins/overlayable/index.js.map +1 -1
  26. package/es5/util/helpers.js +44 -0
  27. package/es5/util/helpers.js.map +1 -1
  28. package/es5/util/legacyEventsMixin.js +48 -0
  29. package/es5/util/legacyEventsMixin.js.map +1 -0
  30. package/lib/components/VOverlay/VOverlay.js +1 -2
  31. package/lib/components/VOverlay/VOverlay.js.map +1 -1
  32. package/lib/components/VProgressCircular/VProgressCircular.js +5 -3
  33. package/lib/components/VProgressCircular/VProgressCircular.js.map +1 -1
  34. package/lib/components/VProgressLinear/VProgressLinear.js +35 -17
  35. package/lib/components/VProgressLinear/VProgressLinear.js.map +1 -1
  36. package/lib/components/VTabs/VTabs.js +1 -1
  37. package/lib/components/VTabs/VTabs.js.map +1 -1
  38. package/lib/components/VTabs/VTabsBar.js.map +1 -1
  39. package/lib/components/VVirtualScroll/VVirtualScroll.js +8 -11
  40. package/lib/components/VVirtualScroll/VVirtualScroll.js.map +1 -1
  41. package/lib/components/VWindow/VWindow.js +7 -3
  42. package/lib/components/VWindow/VWindow.js.map +1 -1
  43. package/lib/components/VWindow/VWindowItem.js +3 -1
  44. package/lib/components/VWindow/VWindowItem.js.map +1 -1
  45. package/lib/framework.js +1 -1
  46. package/lib/install.js +5 -28
  47. package/lib/install.js.map +1 -1
  48. package/lib/mixins/detachable/index.js +3 -4
  49. package/lib/mixins/detachable/index.js.map +1 -1
  50. package/lib/mixins/overlayable/index.js.map +1 -1
  51. package/lib/util/helpers.js +42 -0
  52. package/lib/util/helpers.js.map +1 -1
  53. package/lib/util/legacyEventsMixin.js +37 -0
  54. package/lib/util/legacyEventsMixin.js.map +1 -0
  55. package/package.json +1 -1
  56. package/src/components/VAvatar/__tests__/VAvatar.spec.ts +72 -10
  57. package/src/components/VOverlay/VOverlay.ts +1 -1
  58. package/src/components/VOverlay/__tests__/VOverlay.spec.ts +6 -6
  59. package/src/components/VProgressCircular/VProgressCircular.ts +6 -5
  60. package/src/components/VProgressCircular/__tests__/VProgressCircular.spec.ts +28 -21
  61. package/src/components/VProgressCircular/__tests__/__snapshots__/VProgressCircular.spec.ts.snap +62 -62
  62. package/src/components/VProgressLinear/VProgressLinear.ts +42 -22
  63. package/src/components/VProgressLinear/__tests__/VProgressLinear.spec.ts +378 -71
  64. package/src/components/VProgressLinear/__tests__/__snapshots__/VProgressLinear.spec.ts.snap +53 -79
  65. package/src/components/VSheet/__tests__/VSheet.spec.ts +5 -5
  66. package/src/components/VTabs/VTabs.ts +1 -1
  67. package/src/components/VTabs/VTabsBar.ts +7 -5
  68. package/src/components/VTabs/__tests__/VTab.spec.ts +48 -37
  69. package/src/components/VTabs/__tests__/VTabs.spec.ts +134 -79
  70. package/src/components/VTabs/__tests__/VTabsBar.spec.ts +67 -26
  71. package/src/components/VTabs/__tests__/VTabsSlider.spec.ts +7 -6
  72. package/src/components/VTabs/__tests__/__snapshots__/VTabs.spec.ts.snap +1 -3
  73. package/src/components/VVirtualScroll/VVirtualScroll.ts +14 -13
  74. package/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.ts +26 -19
  75. package/src/components/VWindow/VWindow.ts +9 -5
  76. package/src/components/VWindow/VWindowItem.ts +3 -1
  77. package/src/components/VWindow/__tests__/VWindow.spec.ts +226 -185
  78. package/src/components/VWindow/__tests__/VWindowItem.spec.ts +162 -132
  79. package/src/install.ts +10 -32
  80. package/src/mixins/applicationable/__tests__/applicationable.spec.ts +31 -27
  81. package/src/mixins/colorable/__tests__/colorable.spec.ts +9 -6
  82. package/src/mixins/detachable/index.ts +2 -1
  83. package/src/mixins/elevatable/__tests__/elevatable.spec.ts +14 -13
  84. package/src/mixins/intersectable/__tests__/intersectable.spec.ts +35 -29
  85. package/src/mixins/menuable/__tests__/menuable.spec.ts +76 -33
  86. package/src/mixins/mobile/__tests__/mobile.spec.ts +9 -6
  87. package/src/mixins/overlayable/__tests__/overlayable.spec.ts +32 -24
  88. package/src/mixins/overlayable/index.ts +1 -1
  89. package/src/mixins/proxyable/__tests__/proxyable.spec.ts +18 -17
  90. package/src/mixins/registrable/__tests__/registrable.spec.ts +31 -0
  91. package/src/mixins/rippleable/__tests__/rippleable.spec.ts +10 -9
  92. package/src/mixins/roundable/__tests__/roundable.spec.ts +7 -5
  93. package/src/mixins/routable/__tests__/routable.spec.ts +60 -52
  94. package/src/mixins/scrollable/__tests__/scrollable.spec.ts +56 -27
  95. package/src/mixins/selectable/__tests__/selectable.spec.ts +22 -9
  96. package/src/util/__tests__/helpers.spec.ts +62 -1
  97. package/src/util/helpers.ts +42 -1
  98. package/src/util/legacyEventsMixin.ts +34 -0
@@ -1,17 +1,20 @@
1
1
  import Routable from '../'
2
- import { createLocalVue, mount, Wrapper } from '@vue/test-utils'
3
- import Router from 'vue-router'
4
- import Vue, { VNode, withDirectives } from 'vue'
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<Vue>
8
- let router: Router
9
- let localVue: typeof Vue
7
+ let mountFunction: (options?: object) => Wrapper<any>
8
+ let router: any
10
9
 
11
10
  beforeEach(() => {
12
- router = new Router()
13
- localVue = createLocalVue()
14
- localVue.use(Router)
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
- render (h): VNode {
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
- localVue,
44
- router,
32
+ global: {
33
+ plugins: [router],
34
+ },
45
35
  ...options,
46
36
  })
47
37
  }
48
38
  })
49
- it('should generate exact route link with to="/" and undefined exact', async () => {
39
+
40
+ it('should have correct computed properties', async () => {
50
41
  const wrapper = mountFunction({
51
- propsData: {
42
+ props: {
52
43
  to: '/',
53
44
  },
54
45
  })
55
46
 
56
- expect(wrapper.vm.generateRouteLink().data.props.exact).toBe(true)
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 reflect the link state to isActive', async () => {
51
+ it('should have correct classes computed property', async () => {
60
52
  const wrapper = mountFunction({
61
- propsData: {
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
- // Simulate route changing
69
- wrapper.vm.$router.push('/foo')
59
+ expect(wrapper.vm.classes).toBeDefined()
60
+ })
70
61
 
71
- await wrapper.vm.$nextTick()
72
- await wrapper.vm.$nextTick()
73
- expect(wrapper.vm.isActive).toBe(false)
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.$router.push('/')
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 reflect the link state to isActive if not exact', async () => {
73
+ it('should handle notALink prop', async () => {
82
74
  const wrapper = mountFunction({
83
- propsData: {
84
- to: '/foo',
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
- // Simulate route changing
91
- wrapper.vm.$router.push('/foo')
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
- await wrapper.vm.$nextTick()
94
- await wrapper.vm.$nextTick()
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
- mount,
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) => Wrapper<Instance>
10
+ type Instance = InstanceType<typeof Scrollable>;
11
+ let mountFunction: (options?: object) => VueWrapper<Instance>
14
12
 
15
- beforeEach(() => {
16
- const Mock = {
13
+ const createMockComponent = (options = {}) => {
14
+ return defineComponent({
17
15
  mixins: [Scrollable],
18
- render (h) {
16
+ ...options,
17
+ render () {
19
18
  return h('div', {
20
- directives: [{
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
- propsData: {
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
- currentScroll: 100,
58
- previousScroll: 0,
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
- const wrapper = mountFunction({
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
- propsData: {
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
- savedScroll: 100,
98
- }),
121
+ data () {
122
+ return {
123
+ savedScroll: 100,
124
+ }
125
+ },
99
126
  })
100
127
 
101
- wrapper.setData({ isActive: true })
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
- propsData: {
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
- MountOptions,
8
- Wrapper,
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 = Selectable.extend({
13
- render: h => h('div'),
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?: MountOptions<Instance>) => Wrapper<Instance>
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({ inputValue: true })
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
+ })
@@ -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
+ }