vuetify 2.6.0-beta.0 → 2.6.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.
Files changed (166) hide show
  1. package/dist/json/attributes.json +64 -60
  2. package/dist/json/tags.json +1 -0
  3. package/dist/json/web-types.json +128 -92
  4. package/dist/vuetify.css +37 -33
  5. package/dist/vuetify.css.map +1 -1
  6. package/dist/vuetify.js +244 -146
  7. package/dist/vuetify.js.map +1 -1
  8. package/dist/vuetify.min.css +2 -2
  9. package/dist/vuetify.min.js +2 -2
  10. package/es5/components/VAutocomplete/VAutocomplete.js +20 -2
  11. package/es5/components/VAutocomplete/VAutocomplete.js.map +1 -1
  12. package/es5/components/VCalendar/VCalendarDaily.js +13 -15
  13. package/es5/components/VCalendar/VCalendarDaily.js.map +1 -1
  14. package/es5/components/VCalendar/mixins/calendar-with-events.js +4 -2
  15. package/es5/components/VCalendar/mixins/calendar-with-events.js.map +1 -1
  16. package/es5/components/VCalendar/mixins/mouse.js +1 -1
  17. package/es5/components/VCalendar/mixins/mouse.js.map +1 -1
  18. package/es5/components/VCombobox/VCombobox.js +0 -5
  19. package/es5/components/VCombobox/VCombobox.js.map +1 -1
  20. package/es5/components/VDialog/VDialog.js +4 -2
  21. package/es5/components/VDialog/VDialog.js.map +1 -1
  22. package/es5/components/VList/VListItem.js +8 -1
  23. package/es5/components/VList/VListItem.js.map +1 -1
  24. package/es5/components/VMenu/VMenu.js +1 -1
  25. package/es5/components/VMenu/VMenu.js.map +1 -1
  26. package/es5/components/VOtpInput/VOtpInput.js +14 -25
  27. package/es5/components/VOtpInput/VOtpInput.js.map +1 -1
  28. package/es5/components/VOverlay/VOverlay.js +1 -0
  29. package/es5/components/VOverlay/VOverlay.js.map +1 -1
  30. package/es5/components/VRadioGroup/VRadioGroup.js +7 -0
  31. package/es5/components/VRadioGroup/VRadioGroup.js.map +1 -1
  32. package/es5/components/VRangeSlider/VRangeSlider.js +4 -1
  33. package/es5/components/VRangeSlider/VRangeSlider.js.map +1 -1
  34. package/es5/components/VSelect/VSelect.js +1 -1
  35. package/es5/components/VSelect/VSelect.js.map +1 -1
  36. package/es5/components/VTabs/VTab.js +15 -4
  37. package/es5/components/VTabs/VTab.js.map +1 -1
  38. package/es5/components/VTextField/VTextField.js +6 -1
  39. package/es5/components/VTextField/VTextField.js.map +1 -1
  40. package/es5/components/VTreeview/VTreeviewNode.js +3 -1
  41. package/es5/components/VTreeview/VTreeviewNode.js.map +1 -1
  42. package/es5/components/transitions/createTransition.js +0 -20
  43. package/es5/components/transitions/createTransition.js.map +1 -1
  44. package/es5/directives/click-outside/index.js +21 -10
  45. package/es5/directives/click-outside/index.js.map +1 -1
  46. package/es5/directives/intersect/index.js +16 -12
  47. package/es5/directives/intersect/index.js.map +1 -1
  48. package/es5/directives/mutate/index.js +10 -8
  49. package/es5/directives/mutate/index.js.map +1 -1
  50. package/es5/directives/resize/index.js +11 -8
  51. package/es5/directives/resize/index.js.map +1 -1
  52. package/es5/directives/scroll/index.js +13 -10
  53. package/es5/directives/scroll/index.js.map +1 -1
  54. package/es5/framework.js +1 -1
  55. package/es5/locale/fr.js +1 -1
  56. package/es5/locale/fr.js.map +1 -1
  57. package/es5/mixins/detachable/index.js +32 -14
  58. package/es5/mixins/detachable/index.js.map +1 -1
  59. package/es5/mixins/intersectable/index.js +11 -2
  60. package/es5/mixins/intersectable/index.js.map +1 -1
  61. package/es5/mixins/overlayable/index.js +21 -11
  62. package/es5/mixins/overlayable/index.js.map +1 -1
  63. package/es5/mixins/routable/index.js +9 -3
  64. package/es5/mixins/routable/index.js.map +1 -1
  65. package/lib/components/VAutocomplete/VAutocomplete.js +18 -2
  66. package/lib/components/VAutocomplete/VAutocomplete.js.map +1 -1
  67. package/lib/components/VCalendar/VCalendarDaily.js +9 -9
  68. package/lib/components/VCalendar/VCalendarDaily.js.map +1 -1
  69. package/lib/components/VCalendar/mixins/calendar-with-events.js +4 -2
  70. package/lib/components/VCalendar/mixins/calendar-with-events.js.map +1 -1
  71. package/lib/components/VCalendar/mixins/mouse.js +1 -1
  72. package/lib/components/VCalendar/mixins/mouse.js.map +1 -1
  73. package/lib/components/VCombobox/VCombobox.js +0 -5
  74. package/lib/components/VCombobox/VCombobox.js.map +1 -1
  75. package/lib/components/VDialog/VDialog.js +5 -2
  76. package/lib/components/VDialog/VDialog.js.map +1 -1
  77. package/lib/components/VList/VListItem.js +9 -1
  78. package/lib/components/VList/VListItem.js.map +1 -1
  79. package/lib/components/VMenu/VMenu.js +1 -1
  80. package/lib/components/VMenu/VMenu.js.map +1 -1
  81. package/lib/components/VOtpInput/VOtpInput.js +14 -25
  82. package/lib/components/VOtpInput/VOtpInput.js.map +1 -1
  83. package/lib/components/VOverlay/VOverlay.js +1 -0
  84. package/lib/components/VOverlay/VOverlay.js.map +1 -1
  85. package/lib/components/VRadioGroup/VRadioGroup.js +9 -0
  86. package/lib/components/VRadioGroup/VRadioGroup.js.map +1 -1
  87. package/lib/components/VRangeSlider/VRangeSlider.js +4 -1
  88. package/lib/components/VRangeSlider/VRangeSlider.js.map +1 -1
  89. package/lib/components/VSelect/VSelect.js +1 -1
  90. package/lib/components/VSelect/VSelect.js.map +1 -1
  91. package/lib/components/VTabs/VTab.js +16 -6
  92. package/lib/components/VTabs/VTab.js.map +1 -1
  93. package/lib/components/VTextField/VTextField.js +8 -1
  94. package/lib/components/VTextField/VTextField.js.map +1 -1
  95. package/lib/components/VTreeview/VTreeviewNode.js +3 -1
  96. package/lib/components/VTreeview/VTreeviewNode.js.map +1 -1
  97. package/lib/components/transitions/createTransition.js +0 -6
  98. package/lib/components/transitions/createTransition.js.map +1 -1
  99. package/lib/directives/click-outside/index.js +22 -10
  100. package/lib/directives/click-outside/index.js.map +1 -1
  101. package/lib/directives/intersect/index.js +16 -12
  102. package/lib/directives/intersect/index.js.map +1 -1
  103. package/lib/directives/mutate/index.js +10 -8
  104. package/lib/directives/mutate/index.js.map +1 -1
  105. package/lib/directives/resize/index.js +9 -6
  106. package/lib/directives/resize/index.js.map +1 -1
  107. package/lib/directives/scroll/index.js +9 -6
  108. package/lib/directives/scroll/index.js.map +1 -1
  109. package/lib/framework.js +1 -1
  110. package/lib/locale/fr.js +1 -1
  111. package/lib/locale/fr.js.map +1 -1
  112. package/lib/mixins/detachable/index.js +28 -13
  113. package/lib/mixins/detachable/index.js.map +1 -1
  114. package/lib/mixins/intersectable/index.js +9 -2
  115. package/lib/mixins/intersectable/index.js.map +1 -1
  116. package/lib/mixins/overlayable/index.js +21 -11
  117. package/lib/mixins/overlayable/index.js.map +1 -1
  118. package/lib/mixins/routable/index.js +12 -3
  119. package/lib/mixins/routable/index.js.map +1 -1
  120. package/package.json +2 -2
  121. package/src/components/VAutocomplete/VAutocomplete.ts +15 -2
  122. package/src/components/VCalendar/VCalendarDaily.ts +7 -7
  123. package/src/components/VCalendar/mixins/calendar-with-events.sass +7 -1
  124. package/src/components/VCalendar/mixins/calendar-with-events.ts +3 -3
  125. package/src/components/VCalendar/mixins/mouse.ts +1 -1
  126. package/src/components/VCombobox/VCombobox.ts +0 -5
  127. package/src/components/VCombobox/__tests__/VCombobox-multiple.spec.ts +113 -0
  128. package/src/components/VCombobox/__tests__/VCombobox.spec.ts +30 -0
  129. package/src/components/VDialog/VDialog.ts +4 -2
  130. package/src/components/VImg/__tests__/VImg.spec.ts +1 -1
  131. package/src/components/VList/VListItem.sass +2 -1
  132. package/src/components/VList/VListItem.ts +7 -1
  133. package/src/components/VList/__tests__/VListItem.spec.ts +16 -0
  134. package/src/components/VMenu/VMenu.ts +1 -1
  135. package/src/components/VOtpInput/VOtpInput.sass +13 -16
  136. package/src/components/VOtpInput/VOtpInput.ts +12 -28
  137. package/src/components/VOtpInput/_variables.scss +2 -4
  138. package/src/components/VOverlay/VOverlay.ts +1 -0
  139. package/src/components/VRadioGroup/VRadioGroup.ts +8 -0
  140. package/src/components/VRangeSlider/VRangeSlider.ts +3 -1
  141. package/src/components/VSelect/VSelect.ts +1 -1
  142. package/src/components/VTabs/VTab.ts +14 -4
  143. package/src/components/VTabs/VTabs.sass +5 -2
  144. package/src/components/VTextField/VTextField.ts +8 -3
  145. package/src/components/VTreeview/VTreeviewNode.ts +3 -1
  146. package/src/components/transitions/createTransition.ts +0 -8
  147. package/src/directives/click-outside/__tests__/click-outside-shadow-dom.spec.ts +9 -6
  148. package/src/directives/click-outside/__tests__/click-outside.spec.ts +7 -4
  149. package/src/directives/click-outside/index.ts +19 -10
  150. package/src/directives/intersect/__tests__/intersect.spec.ts +13 -10
  151. package/src/directives/intersect/index.ts +15 -13
  152. package/src/directives/mutate/__tests__/mutate.spec.ts +36 -17
  153. package/src/directives/mutate/index.ts +9 -9
  154. package/src/directives/resize/__tests__/resize.spec.ts +4 -4
  155. package/src/directives/resize/index.ts +11 -6
  156. package/src/directives/scroll/__tests__/scroll.spec.ts +9 -9
  157. package/src/directives/scroll/index.ts +8 -7
  158. package/src/globals.d.ts +10 -12
  159. package/src/locale/fr.ts +1 -1
  160. package/src/mixins/detachable/index.ts +32 -15
  161. package/src/mixins/intersectable/index.ts +11 -2
  162. package/src/mixins/overlayable/index.ts +22 -11
  163. package/src/mixins/routable/__tests__/routable.spec.ts +82 -5
  164. package/src/mixins/routable/index.ts +10 -3
  165. package/src/styles/generic/_transitions.scss +219 -215
  166. package/src/styles/settings/_variables.scss +10 -9
@@ -1,4 +1,4 @@
1
- import { VNodeDirective } from 'vue'
1
+ import { VNode, VNodeDirective } from 'vue'
2
2
 
3
3
  type MutateHandler = (
4
4
  mutationsList: MutationRecord[],
@@ -16,7 +16,7 @@ interface MutateVNodeDirective extends Omit<VNodeDirective, 'modifiers'> {
16
16
  }
17
17
  }
18
18
 
19
- function inserted (el: HTMLElement, binding: MutateVNodeDirective) {
19
+ function inserted (el: HTMLElement, binding: MutateVNodeDirective, vnode: VNode) {
20
20
  const modifiers = binding.modifiers || {}
21
21
  const value = binding.value
22
22
  const callback = typeof value === 'object' ? value.handler : value!
@@ -52,19 +52,19 @@ function inserted (el: HTMLElement, binding: MutateVNodeDirective) {
52
52
  callback(mutationsList, observer)
53
53
 
54
54
  // If has the once modifier, unbind
55
- once && unbind(el)
55
+ once && unbind(el, binding, vnode)
56
56
  })
57
57
 
58
58
  observer.observe(el, options)
59
- el._mutate = { observer }
59
+ el._mutate = Object(el._mutate)
60
+ el._mutate![vnode.context!._uid] = { observer }
60
61
  }
61
62
 
62
- function unbind (el: HTMLElement) {
63
- /* istanbul ignore if */
64
- if (!el._mutate) return
63
+ function unbind (el: HTMLElement, binding: MutateVNodeDirective, vnode: VNode) {
64
+ if (!el._mutate?.[vnode.context!._uid]) return
65
65
 
66
- el._mutate.observer.disconnect()
67
- delete el._mutate
66
+ el._mutate[vnode.context!._uid]!.observer.disconnect()
67
+ delete el._mutate[vnode.context!._uid]
68
68
  }
69
69
 
70
70
  export const Mutate = {
@@ -8,10 +8,10 @@ describe('resize.ts', () => {
8
8
  jest.spyOn(window, 'removeEventListener')
9
9
  const el = {}
10
10
 
11
- Resize.inserted(el as HTMLElement, { value: callback } as any)
11
+ Resize.inserted(el as HTMLElement, { value: callback } as any, { context: { _uid: 1 } } as any)
12
12
  expect(callback).toHaveBeenCalled()
13
13
  expect(window.addEventListener).toHaveBeenCalledWith('resize', callback, { passive: true })
14
- Resize.unbind(el as HTMLElement)
14
+ Resize.unbind(el as HTMLElement, { value: callback } as any, { context: { _uid: 1 } } as any)
15
15
  expect(window.removeEventListener).toHaveBeenCalledWith('resize', callback, { passive: true })
16
16
  })
17
17
 
@@ -21,10 +21,10 @@ describe('resize.ts', () => {
21
21
  jest.spyOn(window, 'removeEventListener')
22
22
  const el = {}
23
23
 
24
- Resize.inserted(el as HTMLElement, { value: callback, modifiers: { quiet: true } } as any)
24
+ Resize.inserted(el as HTMLElement, { value: callback, modifiers: { quiet: true } } as any, { context: { _uid: 1 } } as any)
25
25
  expect(callback).not.toHaveBeenCalled()
26
26
  expect(window.addEventListener).toHaveBeenCalledWith('resize', callback, { passive: true })
27
- Resize.unbind(el as HTMLElement)
27
+ Resize.unbind(el as HTMLElement, { value: callback, modifiers: { quiet: true } } as any, { context: { _uid: 1 } } as any)
28
28
  expect(window.removeEventListener).toHaveBeenCalledWith('resize', callback, { passive: true })
29
29
  })
30
30
  })
@@ -1,16 +1,19 @@
1
1
  import { VNodeDirective } from 'vue/types/vnode'
2
+ import { VNode } from 'vue'
2
3
 
3
4
  interface ResizeVNodeDirective extends VNodeDirective {
4
5
  value?: () => void
5
6
  options?: boolean | AddEventListenerOptions
6
7
  }
7
8
 
8
- function inserted (el: HTMLElement, binding: ResizeVNodeDirective) {
9
+ function inserted (el: HTMLElement, binding: ResizeVNodeDirective, vnode: VNode) {
9
10
  const callback = binding.value!
10
11
  const options = binding.options || { passive: true }
11
12
 
12
13
  window.addEventListener('resize', callback, options)
13
- el._onResize = {
14
+
15
+ el._onResize = Object(el._onResize)
16
+ el._onResize![vnode.context!._uid] = {
14
17
  callback,
15
18
  options,
16
19
  }
@@ -20,12 +23,14 @@ function inserted (el: HTMLElement, binding: ResizeVNodeDirective) {
20
23
  }
21
24
  }
22
25
 
23
- function unbind (el: HTMLElement) {
24
- if (!el._onResize) return
26
+ function unbind (el: HTMLElement, binding: ResizeVNodeDirective, vnode: VNode) {
27
+ if (!el._onResize?.[vnode.context!._uid]) return
28
+
29
+ const { callback, options } = el._onResize[vnode.context!._uid]!
25
30
 
26
- const { callback, options } = el._onResize
27
31
  window.removeEventListener('resize', callback, options)
28
- delete el._onResize
32
+
33
+ delete el._onResize[vnode.context!._uid]
29
34
  }
30
35
 
31
36
  export const Resize = {
@@ -12,7 +12,7 @@ describe('scroll.ts', () => {
12
12
  let vnode
13
13
 
14
14
  beforeEach(() => {
15
- vnode = null as any
15
+ vnode = { context: { _uid: 1 } } as any
16
16
  options = { passive: true }
17
17
  binding = {
18
18
  value: jest.fn(),
@@ -32,7 +32,7 @@ describe('scroll.ts', () => {
32
32
  inserted(el, binding, vnode, vnode)
33
33
 
34
34
  expect(spyOnWindowAddListener).toHaveBeenCalledWith('scroll', binding.value, options)
35
- expect(el._onScroll).toEqual({
35
+ expect(el._onScroll[1]).toEqual({
36
36
  handler: binding.value,
37
37
  options,
38
38
  target: window,
@@ -41,7 +41,7 @@ describe('scroll.ts', () => {
41
41
  unbind(el, binding, vnode, vnode)
42
42
 
43
43
  expect(spyOnWindowRemoveListener).toHaveBeenCalledWith('scroll', binding.value, options)
44
- expect(el._onScroll).toBeUndefined()
44
+ expect(el._onScroll[1]).toBeUndefined()
45
45
  })
46
46
 
47
47
  it('should work with a provided valid querySelector string', () => {
@@ -66,7 +66,7 @@ describe('scroll.ts', () => {
66
66
  inserted(el, binding, vnode, vnode)
67
67
 
68
68
  expect(spyOnFooAddListener).toHaveBeenCalledWith('scroll', binding.value, options)
69
- expect(el._onScroll).toEqual({
69
+ expect(el._onScroll[1]).toEqual({
70
70
  handler: binding.value,
71
71
  options,
72
72
  target,
@@ -75,7 +75,7 @@ describe('scroll.ts', () => {
75
75
  unbind(el, binding, vnode, vnode)
76
76
 
77
77
  expect(spyOnFooRemoveListener).toHaveBeenCalledWith('scroll', binding.value, options)
78
- expect(el._onScroll).toBeUndefined()
78
+ expect(el._onScroll[1]).toBeUndefined()
79
79
 
80
80
  document.body.removeChild(target)
81
81
  })
@@ -86,7 +86,7 @@ describe('scroll.ts', () => {
86
86
  inserted(el, binding, vnode, vnode)
87
87
 
88
88
  expect(el.addEventListener).toHaveBeenCalledWith('scroll', binding.value, options)
89
- expect(el._onScroll).toEqual({
89
+ expect(el._onScroll[1]).toEqual({
90
90
  handler: binding.value,
91
91
  options,
92
92
  target: undefined,
@@ -95,7 +95,7 @@ describe('scroll.ts', () => {
95
95
  unbind(el, binding, vnode, vnode)
96
96
 
97
97
  expect(el.removeEventListener).toHaveBeenCalledWith('scroll', binding.value, options)
98
- expect(el._onScroll).toBeUndefined()
98
+ expect(el._onScroll[1]).toBeUndefined()
99
99
  })
100
100
 
101
101
  it('should not remove listeners if no _onScroll property present', () => {
@@ -111,7 +111,7 @@ describe('scroll.ts', () => {
111
111
 
112
112
  inserted(el, binding, vnode, vnode)
113
113
 
114
- expect(el._onScroll).toEqual({
114
+ expect(el._onScroll[1]).toEqual({
115
115
  handler,
116
116
  target: window,
117
117
  options: { passive: true },
@@ -121,7 +121,7 @@ describe('scroll.ts', () => {
121
121
 
122
122
  inserted(el, binding, vnode, vnode)
123
123
 
124
- expect(el._onScroll).toEqual({
124
+ expect(el._onScroll[1]).toEqual({
125
125
  handler,
126
126
  target: window,
127
127
  options: { passive: false },
@@ -1,5 +1,5 @@
1
1
  import { VNodeDirective } from 'vue/types/vnode'
2
- import { DirectiveOptions } from 'vue'
2
+ import { DirectiveOptions, VNode } from 'vue'
3
3
 
4
4
  interface ScrollVNodeDirective extends Omit<VNodeDirective, 'modifiers'> {
5
5
  value: EventListener | {
@@ -11,7 +11,7 @@ interface ScrollVNodeDirective extends Omit<VNodeDirective, 'modifiers'> {
11
11
  }
12
12
  }
13
13
 
14
- function inserted (el: HTMLElement, binding: ScrollVNodeDirective) {
14
+ function inserted (el: HTMLElement, binding: ScrollVNodeDirective, vnode: VNode) {
15
15
  const { self = false } = binding.modifiers || {}
16
16
  const value = binding.value
17
17
  const options = (typeof value === 'object' && value.options) || { passive: true }
@@ -27,7 +27,8 @@ function inserted (el: HTMLElement, binding: ScrollVNodeDirective) {
27
27
 
28
28
  target.addEventListener('scroll', handler, options)
29
29
 
30
- el._onScroll = {
30
+ el._onScroll = Object(el._onScroll)
31
+ el._onScroll![vnode.context!._uid] = {
31
32
  handler,
32
33
  options,
33
34
  // Don't reference self
@@ -35,13 +36,13 @@ function inserted (el: HTMLElement, binding: ScrollVNodeDirective) {
35
36
  }
36
37
  }
37
38
 
38
- function unbind (el: HTMLElement) {
39
- if (!el._onScroll) return
39
+ function unbind (el: HTMLElement, binding: ScrollVNodeDirective, vnode: VNode) {
40
+ if (!el._onScroll?.[vnode.context!._uid]) return
40
41
 
41
- const { handler, options, target = el } = el._onScroll
42
+ const { handler, options, target = el } = el._onScroll[vnode.context!._uid]!
42
43
 
43
44
  target.removeEventListener('scroll', handler, options)
44
- delete el._onScroll
45
+ delete el._onScroll[vnode.context!._uid]
45
46
  }
46
47
 
47
48
  export const Scroll = {
package/src/globals.d.ts CHANGED
@@ -29,15 +29,14 @@ declare global {
29
29
  }
30
30
 
31
31
  interface HTMLElement {
32
- _clickOutside?: {
33
- lastMousedownWasOutside: boolean
32
+ _clickOutside?: Record<number, {
34
33
  onClick: EventListener
35
34
  onMousedown: EventListener
36
- }
37
- _onResize?: {
35
+ } | undefined> & { lastMousedownWasOutside: boolean }
36
+ _onResize?: Record<number, {
38
37
  callback: () => void
39
38
  options?: boolean | AddEventListenerOptions
40
- }
39
+ } | undefined>
41
40
  _ripple?: {
42
41
  enabled?: boolean
43
42
  centered?: boolean
@@ -48,18 +47,18 @@ declare global {
48
47
  showTimer?: number
49
48
  showTimerCommit?: (() => void) | null
50
49
  }
51
- _observe?: {
50
+ _observe?: Record<number, {
52
51
  init: boolean
53
52
  observer: IntersectionObserver
54
- }
55
- _mutate?: {
53
+ } | undefined>
54
+ _mutate?: Record<number, {
56
55
  observer: MutationObserver
57
- }
58
- _onScroll?: {
56
+ } | undefined>
57
+ _onScroll?: Record<number, {
59
58
  handler: EventListenerOrEventListenerObject
60
59
  options: boolean | AddEventListenerOptions
61
60
  target?: EventTarget
62
- }
61
+ } | undefined>
63
62
  _touchHandlers?: {
64
63
  [_uid: number]: TouchStoredHandlers
65
64
  }
@@ -70,7 +69,6 @@ declare global {
70
69
  width: string
71
70
  height: string
72
71
  }
73
- _initialDisplay?: [string, string]
74
72
  }
75
73
 
76
74
  interface WheelEvent {
package/src/locale/fr.ts CHANGED
@@ -63,7 +63,7 @@ export default {
63
63
  },
64
64
  rating: {
65
65
  ariaLabel: {
66
- icon: 'Rating {0} of {1}',
66
+ icon: 'Note de {0} sur {1}',
67
67
  },
68
68
  },
69
69
  }
@@ -25,6 +25,14 @@ function validateAttachTarget (val: any) {
25
25
  return val.nodeType === Node.ELEMENT_NODE
26
26
  }
27
27
 
28
+ function removeActivator (activator: VNode[]) {
29
+ activator.forEach(node => {
30
+ node.elm &&
31
+ node.elm.parentNode &&
32
+ node.elm.parentNode.removeChild(node.elm)
33
+ })
34
+ }
35
+
28
36
  /* @vue/component */
29
37
  export default mixins<options &
30
38
  /* eslint-disable indent */
@@ -87,24 +95,33 @@ export default mixins<options &
87
95
  },
88
96
 
89
97
  beforeDestroy () {
90
- // IE11 Fix
91
- try {
92
- if (
93
- this.$refs.content &&
94
- this.$refs.content.parentNode
95
- ) {
96
- this.$refs.content.parentNode.removeChild(this.$refs.content)
97
- }
98
+ if (
99
+ this.$refs.content &&
100
+ this.$refs.content.parentNode
101
+ ) {
102
+ this.$refs.content.parentNode.removeChild(this.$refs.content)
103
+ }
104
+ },
98
105
 
99
- if (this.activatorNode) {
100
- const activator = Array.isArray(this.activatorNode) ? this.activatorNode : [this.activatorNode]
101
- activator.forEach(node => {
102
- node.elm &&
103
- node.elm.parentNode &&
104
- node.elm.parentNode.removeChild(node.elm)
106
+ destroyed () {
107
+ if (this.activatorNode) {
108
+ const activator = Array.isArray(this.activatorNode) ? this.activatorNode : [this.activatorNode]
109
+ if (this.$el.isConnected) {
110
+ // Component has been destroyed but the element still exists, we must be in a transition
111
+ // Wait for the transition to finish before cleaning up the detached activator
112
+ const observer = new MutationObserver(list => {
113
+ if (
114
+ list.some(record => Array.from(record.removedNodes).includes(this.$el))
115
+ ) {
116
+ observer.disconnect()
117
+ removeActivator(activator)
118
+ }
105
119
  })
120
+ observer.observe(this.$el.parentNode!, { subtree: false, childList: true })
121
+ } else {
122
+ removeActivator(activator)
106
123
  }
107
- } catch (e) { console.log(e) } /* eslint-disable-line no-console */
124
+ }
108
125
  },
109
126
 
110
127
  methods: {
@@ -11,19 +11,28 @@ export default function intersectable (options: { onVisible: string[] }) {
11
11
  return Vue.extend({
12
12
  name: 'intersectable',
13
13
 
14
+ data: () => ({
15
+ isIntersecting: false,
16
+ }),
17
+
14
18
  mounted () {
15
19
  Intersect.inserted(this.$el as HTMLElement, {
16
20
  name: 'intersect',
17
21
  value: this.onObserve,
18
- })
22
+ }, this.$vnode)
19
23
  },
20
24
 
21
25
  destroyed () {
22
- Intersect.unbind(this.$el as HTMLElement)
26
+ Intersect.unbind(this.$el as HTMLElement, {
27
+ name: 'intersect',
28
+ value: this.onObserve,
29
+ }, this.$vnode)
23
30
  },
24
31
 
25
32
  methods: {
26
33
  onObserve (entries: IntersectionObserverEntry[], observer: IntersectionObserver, isIntersecting: boolean) {
34
+ this.isIntersecting = isIntersecting
35
+
27
36
  if (!isIntersecting) return
28
37
 
29
38
  for (let i = 0, length = options.onVisible.length; i < length; i++) {
@@ -156,20 +156,32 @@ export default Vue.extend<Vue & Toggleable & Stackable & options>().extend({
156
156
  if (!el || el.nodeType !== Node.ELEMENT_NODE) return false
157
157
 
158
158
  const style = window.getComputedStyle(el)
159
- return ['auto', 'scroll'].includes(style.overflowY!) && el.scrollHeight > el.clientHeight
159
+ return ((['auto', 'scroll'].includes(style.overflowY!) || el.tagName === 'SELECT') && el.scrollHeight > el.clientHeight) ||
160
+ ((['auto', 'scroll'].includes(style.overflowX!)) && el.scrollWidth > el.clientWidth)
160
161
  },
161
- shouldScroll (el: Element, delta: number): boolean {
162
+ shouldScroll (el: Element, e: WheelEvent): boolean {
162
163
  if (el.hasAttribute('data-app')) return false
163
164
 
164
- const alreadyAtTop = el.scrollTop === 0
165
- const alreadyAtBottom = el.scrollTop + el.clientHeight === el.scrollHeight
165
+ const dir = e.shiftKey || e.deltaX ? 'x' : 'y'
166
+ const delta = dir === 'y' ? e.deltaY : e.deltaX || e.deltaY
167
+
168
+ let alreadyAtStart: boolean
169
+ let alreadyAtEnd: boolean
170
+ if (dir === 'y') {
171
+ alreadyAtStart = el.scrollTop === 0
172
+ alreadyAtEnd = el.scrollTop + el.clientHeight === el.scrollHeight
173
+ } else {
174
+ alreadyAtStart = el.scrollLeft === 0
175
+ alreadyAtEnd = el.scrollLeft + el.clientWidth === el.scrollWidth
176
+ }
177
+
166
178
  const scrollingUp = delta < 0
167
179
  const scrollingDown = delta > 0
168
180
 
169
- if (!alreadyAtTop && scrollingUp) return true
170
- if (!alreadyAtBottom && scrollingDown) return true
171
- if ((alreadyAtTop || alreadyAtBottom)) {
172
- return this.shouldScroll(el.parentNode as Element, delta)
181
+ if (!alreadyAtStart && scrollingUp) return true
182
+ if (!alreadyAtEnd && scrollingDown) return true
183
+ if ((alreadyAtStart || alreadyAtEnd)) {
184
+ return this.shouldScroll(el.parentNode as Element, e)
173
185
  }
174
186
 
175
187
  return false
@@ -185,14 +197,13 @@ export default Vue.extend<Vue & Toggleable & Stackable & options>().extend({
185
197
  },
186
198
  checkPath (e: WheelEvent) {
187
199
  const path = composedPath(e)
188
- const delta = e.deltaY
189
200
 
190
201
  if (e.type === 'keydown' && path[0] === document.body) {
191
202
  const dialog = this.$refs.dialog
192
203
  // getSelection returns null in firefox in some edge cases, can be ignored
193
204
  const selected = window.getSelection()!.anchorNode as Element
194
205
  if (dialog && this.hasScrollbar(dialog) && this.isInside(selected, dialog)) {
195
- return !this.shouldScroll(dialog, delta)
206
+ return !this.shouldScroll(dialog, e)
196
207
  }
197
208
  return true
198
209
  }
@@ -204,7 +215,7 @@ export default Vue.extend<Vue & Toggleable & Stackable & options>().extend({
204
215
  if (el === document.documentElement) return true
205
216
  if (el === this.$refs.content) return true
206
217
 
207
- if (this.hasScrollbar(el as Element)) return !this.shouldScroll(el as Element, delta)
218
+ if (this.hasScrollbar(el as Element)) return !this.shouldScroll(el as Element, e)
208
219
  }
209
220
 
210
221
  return true
@@ -1,12 +1,50 @@
1
1
  import Routable from '../'
2
- import { mount } from '@vue/test-utils'
2
+ import { createLocalVue, mount, Wrapper } from '@vue/test-utils'
3
+ import Router from 'vue-router'
4
+ import Vue, { VNode } from 'vue'
3
5
 
4
6
  describe('routable.ts', () => {
7
+ let mountFunction: (options?: object) => Wrapper<Vue>
8
+ let router: Router
9
+ let localVue: typeof Vue
10
+
11
+ beforeEach(() => {
12
+ router = new Router()
13
+ localVue = createLocalVue()
14
+ localVue.use(Router)
15
+
16
+ mountFunction = (options = {}) => {
17
+ return mount({
18
+ mixins: [Routable],
19
+ props: {
20
+ activeClass: {
21
+ default: 'active',
22
+ },
23
+ exactActiveClass: {
24
+ default: 'exact-active',
25
+ },
26
+ },
27
+ render (h): VNode {
28
+ const { tag, data } = this.generateRouteLink()
29
+
30
+ data.attrs = {
31
+ ...data.attrs,
32
+ }
33
+ data.on = {
34
+ ...data.on,
35
+ }
36
+
37
+ return h(tag, data, this.$slots.default)
38
+ },
39
+ }, {
40
+ localVue,
41
+ router,
42
+ ...options,
43
+ })
44
+ }
45
+ })
5
46
  it('should generate exact route link with to="/" and undefined exact', async () => {
6
- const wrapper = mount({
7
- mixins: [Routable],
8
- render: h => h('div'),
9
- }, {
47
+ const wrapper = mountFunction({
10
48
  propsData: {
11
49
  to: '/',
12
50
  },
@@ -14,4 +52,43 @@ describe('routable.ts', () => {
14
52
 
15
53
  expect(wrapper.vm.generateRouteLink().data.props.exact).toBe(true)
16
54
  })
55
+
56
+ it('should reflect the link state to isActive', async () => {
57
+ const wrapper = mountFunction({
58
+ propsData: {
59
+ to: '/',
60
+ },
61
+ })
62
+ await wrapper.vm.$nextTick()
63
+ expect(wrapper.vm.isActive).toBe(true)
64
+
65
+ // Simulate route changing
66
+ wrapper.vm.$router.push('/foo')
67
+
68
+ await wrapper.vm.$nextTick()
69
+ await wrapper.vm.$nextTick()
70
+ expect(wrapper.vm.isActive).toBe(false)
71
+
72
+ wrapper.vm.$router.push('/')
73
+ await wrapper.vm.$nextTick()
74
+ await wrapper.vm.$nextTick()
75
+ expect(wrapper.vm.isActive).toBe(true)
76
+ })
77
+
78
+ it('should reflect the link state to isActive if not exact', async () => {
79
+ const wrapper = mountFunction({
80
+ propsData: {
81
+ to: '/foo',
82
+ },
83
+ })
84
+ await wrapper.vm.$nextTick()
85
+ expect(wrapper.vm.isActive).toBe(false)
86
+
87
+ // Simulate route changing
88
+ wrapper.vm.$router.push('/foo')
89
+
90
+ await wrapper.vm.$nextTick()
91
+ await wrapper.vm.$nextTick()
92
+ expect(wrapper.vm.isActive).toBe(true)
93
+ })
17
94
  })
@@ -75,6 +75,10 @@ export default Vue.extend({
75
75
  $route: 'onRouteChange',
76
76
  },
77
77
 
78
+ mounted () {
79
+ this.onRouteChange()
80
+ },
81
+
78
82
  methods: {
79
83
  click (e: MouseEvent): void {
80
84
  this.$emit('click', e)
@@ -140,16 +144,19 @@ export default Vue.extend({
140
144
  onRouteChange () {
141
145
  if (!this.to || !this.$refs.link || !this.$route) return
142
146
  const activeClass = `${this.activeClass} ${this.proxyClass || ''}`.trim()
147
+ const exactActiveClass = `${this.exactActiveClass} ${this.proxyClass || ''}`.trim() || activeClass
143
148
 
144
- const path = `_vnode.data.class.${activeClass}`
149
+ const path = '_vnode.data.class.' + (this.exact ? exactActiveClass : activeClass)
145
150
 
146
151
  this.$nextTick(() => {
147
152
  /* istanbul ignore else */
148
- if (getObjectValueByPath(this.$refs.link, path)) {
153
+ if (!getObjectValueByPath(this.$refs.link, path) === this.isActive) {
149
154
  this.toggle()
150
155
  }
151
156
  })
152
157
  },
153
- toggle: () => { /* noop */ },
158
+ toggle () {
159
+ this.isActive = !this.isActive
160
+ },
154
161
  },
155
162
  })