wave-ui 1.48.0 → 1.49.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.
- package/dist/wave-ui.cjs.js +1 -1
- package/dist/wave-ui.es.js +125 -119
- package/dist/wave-ui.umd.js +1 -1
- package/package.json +1 -1
- package/src/wave-ui/components/w-menu.vue +24 -83
- package/src/wave-ui/components/w-notification-manager.vue +9 -2
- package/src/wave-ui/components/w-tooltip.vue +22 -75
- package/src/wave-ui/mixins/detachable.js +134 -2
package/package.json
CHANGED
|
@@ -74,26 +74,16 @@ export default {
|
|
|
74
74
|
menuClass: { type: [String, Object, Array] },
|
|
75
75
|
titleClass: { type: [String, Object, Array] },
|
|
76
76
|
contentClass: { type: [String, Object, Array] },
|
|
77
|
-
// Position.
|
|
78
77
|
arrow: { type: Boolean }, // The small triangle pointing toward the activator.
|
|
79
|
-
detachTo: { type: [String, Boolean, Object], deprecated: true },
|
|
80
|
-
appendTo: { type: [String, Boolean, Object] },
|
|
81
|
-
fixed: { type: Boolean },
|
|
82
|
-
top: { type: Boolean },
|
|
83
|
-
bottom: { type: Boolean },
|
|
84
|
-
left: { type: Boolean },
|
|
85
|
-
right: { type: Boolean },
|
|
86
|
-
alignTop: { type: Boolean },
|
|
87
|
-
alignBottom: { type: Boolean },
|
|
88
|
-
alignLeft: { type: Boolean },
|
|
89
|
-
alignRight: { type: Boolean },
|
|
90
|
-
zIndex: { type: [Number, String, Boolean] },
|
|
91
78
|
minWidth: { type: [Number, String] }, // can be like: `40`, `5em`, `activator`.
|
|
92
79
|
overlay: { type: Boolean },
|
|
93
80
|
overlayClass: { type: [String, Object, Array] },
|
|
94
81
|
overlayProps: { type: Object }, // Allow passing down an object of props to the w-overlay component.
|
|
95
82
|
persistent: { type: Boolean },
|
|
96
|
-
|
|
83
|
+
delay: { type: Number }
|
|
84
|
+
// Other props in the detachable mixin:
|
|
85
|
+
// detachTo, appendTo, fixed, top, bottom, left, right, alignTop, alignBottom, alignLeft,
|
|
86
|
+
// alignRight, noPosition, zIndex, activator.
|
|
97
87
|
},
|
|
98
88
|
|
|
99
89
|
emits: ['input', 'update:modelValue', 'open', 'close'],
|
|
@@ -107,7 +97,6 @@ export default {
|
|
|
107
97
|
top: 0,
|
|
108
98
|
left: 0
|
|
109
99
|
},
|
|
110
|
-
activatorEl: null,
|
|
111
100
|
activatorWidth: 0,
|
|
112
101
|
detachableEl: null,
|
|
113
102
|
timeoutId: null
|
|
@@ -118,32 +107,15 @@ export default {
|
|
|
118
107
|
* Other computed in the detachable mixin:
|
|
119
108
|
* - `appendToTarget`
|
|
120
109
|
* - `detachableParentEl`
|
|
110
|
+
* - `activatorEl`
|
|
111
|
+
* - `position`
|
|
112
|
+
* - `alignment`
|
|
121
113
|
**/
|
|
122
114
|
|
|
123
115
|
transitionName () {
|
|
124
116
|
return this.transition || 'scale-fade'
|
|
125
117
|
},
|
|
126
118
|
|
|
127
|
-
position () {
|
|
128
|
-
return (
|
|
129
|
-
(this.top && 'top') ||
|
|
130
|
-
(this.bottom && 'bottom') ||
|
|
131
|
-
(this.left && 'left') ||
|
|
132
|
-
(this.right && 'right') ||
|
|
133
|
-
'bottom'
|
|
134
|
-
)
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
alignment () {
|
|
138
|
-
return (
|
|
139
|
-
(['top', 'bottom'].includes(this.position) && this.alignLeft && 'left') ||
|
|
140
|
-
(['top', 'bottom'].includes(this.position) && this.alignRight && 'right') ||
|
|
141
|
-
(['left', 'right'].includes(this.position) && this.alignTop && 'top') ||
|
|
142
|
-
(['left', 'right'].includes(this.position) && this.alignBottom && 'bottom') ||
|
|
143
|
-
''
|
|
144
|
-
)
|
|
145
|
-
},
|
|
146
|
-
|
|
147
119
|
menuMinWidth () {
|
|
148
120
|
if (this.minWidth === 'activator') return this.activatorWidth ? `${this.activatorWidth}px` : 0
|
|
149
121
|
else return isNaN(this.minWidth) ? this.minWidth : (this.minWidth ? `${this.minWidth}px` : 0)
|
|
@@ -197,8 +169,8 @@ export default {
|
|
|
197
169
|
|
|
198
170
|
if (this.showOnHover) {
|
|
199
171
|
handlers = {
|
|
200
|
-
focus: this.
|
|
201
|
-
blur: this.
|
|
172
|
+
focus: this.toggle,
|
|
173
|
+
blur: this.toggle,
|
|
202
174
|
mouseenter: e => {
|
|
203
175
|
this.hoveringActivator = true
|
|
204
176
|
this.open(e)
|
|
@@ -213,10 +185,10 @@ export default {
|
|
|
213
185
|
}
|
|
214
186
|
// Check the window exists: SSR-proof.
|
|
215
187
|
if (typeof window !== 'undefined' && 'ontouchstart' in window) {
|
|
216
|
-
handlers.click = this.
|
|
188
|
+
handlers.click = this.toggle
|
|
217
189
|
}
|
|
218
190
|
}
|
|
219
|
-
else handlers = { click: this.
|
|
191
|
+
else handlers = { click: this.toggle }
|
|
220
192
|
return handlers
|
|
221
193
|
}
|
|
222
194
|
},
|
|
@@ -233,7 +205,7 @@ export default {
|
|
|
233
205
|
**/
|
|
234
206
|
|
|
235
207
|
// ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
|
|
236
|
-
|
|
208
|
+
toggle (e) {
|
|
237
209
|
let shouldShowMenu = this.detachableVisible
|
|
238
210
|
if ('ontouchstart' in window && this.showOnHover && e.type === 'click') {
|
|
239
211
|
shouldShowMenu = !shouldShowMenu
|
|
@@ -250,19 +222,22 @@ export default {
|
|
|
250
222
|
|
|
251
223
|
this.timeoutId = clearTimeout(this.timeoutId)
|
|
252
224
|
|
|
253
|
-
if (shouldShowMenu)
|
|
254
|
-
this.$emit('update:modelValue', (this.detachableVisible = true))
|
|
255
|
-
this.$emit('input', true)
|
|
256
|
-
this.$emit('open')
|
|
257
|
-
|
|
258
|
-
this.open(e)
|
|
259
|
-
}
|
|
225
|
+
if (shouldShowMenu) this.open(e)
|
|
260
226
|
else this.close()
|
|
261
227
|
},
|
|
262
228
|
|
|
263
229
|
// ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
|
|
264
230
|
async open (e) {
|
|
231
|
+
// A tiny delay may help positioning the detachable correctly in case of multiple activators
|
|
232
|
+
// with different menu contents.
|
|
233
|
+
if (this.delay) await new Promise(resolve => setTimeout(resolve, this.delay))
|
|
234
|
+
|
|
265
235
|
this.detachableVisible = true
|
|
236
|
+
|
|
237
|
+
// If the activator is external, there might be multiple,
|
|
238
|
+
// so on open, the activator will be set to the event target.
|
|
239
|
+
if (this.activator) this.activatorEl = e.target
|
|
240
|
+
|
|
266
241
|
await this.insertInDOM()
|
|
267
242
|
|
|
268
243
|
if (this.minWidth === 'activator') this.activatorWidth = this.activatorEl.offsetWidth
|
|
@@ -310,43 +285,9 @@ export default {
|
|
|
310
285
|
document.removeEventListener('mousedown', this.onOutsideMousedown)
|
|
311
286
|
window.removeEventListener('resize', this.onResize)
|
|
312
287
|
}
|
|
313
|
-
},
|
|
314
|
-
|
|
315
|
-
mounted () {
|
|
316
|
-
const wrapper = this.$el
|
|
317
|
-
this.activatorEl = wrapper.firstElementChild
|
|
318
|
-
|
|
319
|
-
// Unwrap the activator element.
|
|
320
|
-
wrapper.parentNode.insertBefore(this.activatorEl, wrapper)
|
|
321
|
-
|
|
322
|
-
// Unwrap the overlay.
|
|
323
|
-
if (this.overlay) {
|
|
324
|
-
this.overlayEl = this.$refs.overlay?.$el
|
|
325
|
-
wrapper.parentNode.insertBefore(this.overlayEl, wrapper)
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (this.value) this.toggleMenu({ type: 'click', target: this.activatorEl })
|
|
329
|
-
},
|
|
330
|
-
|
|
331
|
-
beforeDestroy () {
|
|
332
|
-
this.removeFromDOM()
|
|
333
|
-
if (this.overlay && this.overlayEl.parentNode) this.overlayEl.remove()
|
|
334
|
-
if (this.activatorEl && this.activatorEl.parentNode) this.activatorEl.remove()
|
|
335
|
-
},
|
|
336
|
-
|
|
337
|
-
watch: {
|
|
338
|
-
value (bool) {
|
|
339
|
-
if (!!bool !== this.detachableVisible) this.toggleMenu({ type: 'click', target: this.activatorEl })
|
|
340
|
-
},
|
|
341
|
-
detachTo () {
|
|
342
|
-
this.removeFromDOM()
|
|
343
|
-
this.insertInDOM()
|
|
344
|
-
},
|
|
345
|
-
appendTo () {
|
|
346
|
-
this.removeFromDOM()
|
|
347
|
-
this.insertInDOM()
|
|
348
|
-
}
|
|
349
288
|
}
|
|
289
|
+
|
|
290
|
+
// watch, mounted & beforeDestroy hooks are set in the detachable.js mixin.
|
|
350
291
|
}
|
|
351
292
|
</script>
|
|
352
293
|
|
|
@@ -11,8 +11,8 @@ transition-group(
|
|
|
11
11
|
:key="notif._uid"
|
|
12
12
|
v-model="notif._value"
|
|
13
13
|
@close="notifManager.dismiss(notif._uid)"
|
|
14
|
-
v-bind="notif")
|
|
15
|
-
|
|
14
|
+
v-bind="notifProps(notif)")
|
|
15
|
+
div(v-html="notif.message")
|
|
16
16
|
</template>
|
|
17
17
|
|
|
18
18
|
<script>
|
|
@@ -42,6 +42,13 @@ export default {
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
|
|
45
|
+
methods: {
|
|
46
|
+
notifProps (notif) {
|
|
47
|
+
const { _value, _uid, message, timeout, ...props } = notif
|
|
48
|
+
return props
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
|
|
45
52
|
created () {
|
|
46
53
|
this.notifManager = new NotificationManager()
|
|
47
54
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template lang="pug">
|
|
2
2
|
.w-tooltip-wrap
|
|
3
|
-
slot(name="activator" :on="
|
|
3
|
+
slot(name="activator" :on="activatorEventHandlers")
|
|
4
4
|
transition(:name="transitionName" appear)
|
|
5
5
|
.w-tooltip(v-if="detachableVisible" ref="detachable" :class="classes" :style="styles")
|
|
6
6
|
slot
|
|
@@ -36,21 +36,11 @@ export default {
|
|
|
36
36
|
round: { type: Boolean },
|
|
37
37
|
transition: { type: String },
|
|
38
38
|
tooltipClass: { type: [String, Object, Array] },
|
|
39
|
-
// Position.
|
|
40
|
-
detachTo: { type: [String, Boolean, Object], deprecated: true },
|
|
41
|
-
appendTo: { type: [String, Boolean, Object] },
|
|
42
|
-
fixed: { type: Boolean },
|
|
43
|
-
top: { type: Boolean },
|
|
44
|
-
bottom: { type: Boolean },
|
|
45
|
-
left: { type: Boolean },
|
|
46
|
-
right: { type: Boolean },
|
|
47
|
-
alignTop: { type: Boolean },
|
|
48
|
-
alignBottom: { type: Boolean },
|
|
49
|
-
alignLeft: { type: Boolean },
|
|
50
|
-
alignRight: { type: Boolean },
|
|
51
|
-
zIndex: { type: [Number, String, Boolean] },
|
|
52
39
|
persistent: { type: Boolean },
|
|
53
|
-
|
|
40
|
+
delay: { type: Number }
|
|
41
|
+
// Other props in the detachable mixin:
|
|
42
|
+
// detachTo, appendTo, fixed, top, bottom, left, right, alignTop, alignBottom, alignLeft,
|
|
43
|
+
// alignRight, noPosition, zIndex, activator.
|
|
54
44
|
},
|
|
55
45
|
|
|
56
46
|
emits: ['input', 'update:modelValue', 'open', 'close'],
|
|
@@ -58,12 +48,11 @@ export default {
|
|
|
58
48
|
data: () => ({
|
|
59
49
|
detachableVisible: false,
|
|
60
50
|
hoveringActivator: false,
|
|
61
|
-
// The
|
|
51
|
+
// The tooltip computed top & left coordinates.
|
|
62
52
|
detachableCoords: {
|
|
63
53
|
top: 0,
|
|
64
54
|
left: 0
|
|
65
55
|
},
|
|
66
|
-
activatorEl: null,
|
|
67
56
|
detachableEl: null,
|
|
68
57
|
timeoutId: null
|
|
69
58
|
}),
|
|
@@ -73,6 +62,9 @@ export default {
|
|
|
73
62
|
* Other computed in the detachable mixin:
|
|
74
63
|
* - `appendToTarget`
|
|
75
64
|
* - `detachableParentEl`
|
|
65
|
+
* - `activatorEl`
|
|
66
|
+
* - `position`
|
|
67
|
+
* - `alignment`
|
|
76
68
|
**/
|
|
77
69
|
|
|
78
70
|
tooltipClasses () {
|
|
@@ -84,26 +76,6 @@ export default {
|
|
|
84
76
|
return this.transition || `w-tooltip-slide-fade-${direction}`
|
|
85
77
|
},
|
|
86
78
|
|
|
87
|
-
position () {
|
|
88
|
-
return (
|
|
89
|
-
(this.top && 'top') ||
|
|
90
|
-
(this.bottom && 'bottom') ||
|
|
91
|
-
(this.left && 'left') ||
|
|
92
|
-
(this.right && 'right') ||
|
|
93
|
-
'bottom'
|
|
94
|
-
)
|
|
95
|
-
},
|
|
96
|
-
|
|
97
|
-
alignment () {
|
|
98
|
-
return (
|
|
99
|
-
(['top', 'bottom'].includes(this.position) && this.alignLeft && 'left') ||
|
|
100
|
-
(['top', 'bottom'].includes(this.position) && this.alignRight && 'right') ||
|
|
101
|
-
(['left', 'right'].includes(this.position) && this.alignTop && 'top') ||
|
|
102
|
-
(['left', 'right'].includes(this.position) && this.alignBottom && 'bottom') ||
|
|
103
|
-
''
|
|
104
|
-
)
|
|
105
|
-
},
|
|
106
|
-
|
|
107
79
|
classes () {
|
|
108
80
|
return {
|
|
109
81
|
[this.color]: this.color,
|
|
@@ -130,7 +102,7 @@ export default {
|
|
|
130
102
|
}
|
|
131
103
|
},
|
|
132
104
|
|
|
133
|
-
|
|
105
|
+
activatorEventHandlers () {
|
|
134
106
|
let handlers = {}
|
|
135
107
|
if (this.showOnClick) handlers = { click: this.toggle }
|
|
136
108
|
else {
|
|
@@ -176,19 +148,22 @@ export default {
|
|
|
176
148
|
else if (['mouseleave', 'blur'].includes(e.type) && !this.showOnClick) shouldShowTooltip = false
|
|
177
149
|
|
|
178
150
|
this.timeoutId = clearTimeout(this.timeoutId)
|
|
179
|
-
if (shouldShowTooltip)
|
|
180
|
-
this.$emit('update:modelValue', (this.detachableVisible = true))
|
|
181
|
-
this.$emit('input', true)
|
|
182
|
-
this.$emit('open')
|
|
183
|
-
|
|
184
|
-
this.open(e)
|
|
185
|
-
}
|
|
151
|
+
if (shouldShowTooltip) this.open(e)
|
|
186
152
|
else this.close()
|
|
187
153
|
},
|
|
188
154
|
|
|
189
155
|
// ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
|
|
190
156
|
async open (e) {
|
|
157
|
+
// A tiny delay may help positioning the detachable correctly in case of multiple activators
|
|
158
|
+
// with different menu contents.
|
|
159
|
+
if (this.delay) await new Promise(resolve => setTimeout(resolve, this.delay))
|
|
160
|
+
|
|
191
161
|
this.detachableVisible = true
|
|
162
|
+
|
|
163
|
+
// If the activator is external, there might be multiple,
|
|
164
|
+
// so on open, the activator will be set to the event target.
|
|
165
|
+
if (this.activator) this.activatorEl = e.target
|
|
166
|
+
|
|
192
167
|
await this.insertInDOM()
|
|
193
168
|
|
|
194
169
|
if (this.minWidth === 'activator') this.activatorWidth = this.activatorEl.offsetWidth
|
|
@@ -236,37 +211,9 @@ export default {
|
|
|
236
211
|
document.removeEventListener('mousedown', this.onOutsideMousedown)
|
|
237
212
|
window.removeEventListener('resize', this.onResize)
|
|
238
213
|
}
|
|
239
|
-
},
|
|
240
|
-
|
|
241
|
-
mounted () {
|
|
242
|
-
const wrapper = this.$el
|
|
243
|
-
this.activatorEl = wrapper.firstElementChild
|
|
244
|
-
|
|
245
|
-
// Unwrap the activator element.
|
|
246
|
-
wrapper.parentNode.insertBefore(this.activatorEl, wrapper)
|
|
247
|
-
|
|
248
|
-
if (this.value) this.toggle({ type: 'click', target: this.activatorEl })
|
|
249
|
-
},
|
|
250
|
-
|
|
251
|
-
beforeDestroy () {
|
|
252
|
-
this.removeFromDOM()
|
|
253
|
-
|
|
254
|
-
if (this.activatorEl && this.activatorEl.parentNode) this.activatorEl.remove()
|
|
255
|
-
},
|
|
256
|
-
|
|
257
|
-
watch: {
|
|
258
|
-
value (bool) {
|
|
259
|
-
if (bool !== this.detachableVisible) this.toggle({ type: 'click', target: this.activatorEl })
|
|
260
|
-
},
|
|
261
|
-
detachTo () {
|
|
262
|
-
this.removeFromDOM()
|
|
263
|
-
this.insertInDOM()
|
|
264
|
-
},
|
|
265
|
-
appendTo () {
|
|
266
|
-
this.removeFromDOM()
|
|
267
|
-
this.insertInDOM()
|
|
268
|
-
}
|
|
269
214
|
}
|
|
215
|
+
|
|
216
|
+
// watch, mounted & beforeDestroy hooks are set in the detachable.js mixin.
|
|
270
217
|
}
|
|
271
218
|
</script>
|
|
272
219
|
|
|
@@ -7,6 +7,33 @@
|
|
|
7
7
|
import { consoleWarn } from '../utils/console'
|
|
8
8
|
|
|
9
9
|
export default {
|
|
10
|
+
props: {
|
|
11
|
+
// Position.
|
|
12
|
+
detachTo: { type: [String, Boolean, Object], deprecated: true },
|
|
13
|
+
appendTo: { type: [String, Boolean, Object] },
|
|
14
|
+
fixed: { type: Boolean },
|
|
15
|
+
top: { type: Boolean },
|
|
16
|
+
bottom: { type: Boolean },
|
|
17
|
+
left: { type: Boolean },
|
|
18
|
+
right: { type: Boolean },
|
|
19
|
+
alignTop: { type: Boolean },
|
|
20
|
+
alignBottom: { type: Boolean },
|
|
21
|
+
alignLeft: { type: Boolean },
|
|
22
|
+
alignRight: { type: Boolean },
|
|
23
|
+
noPosition: { type: Boolean },
|
|
24
|
+
zIndex: { type: [Number, String, Boolean] },
|
|
25
|
+
activator: { type: String } // Optionally designate an external activator.
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
data: () => ({
|
|
29
|
+
// The event listeners handlers have to be removed the exact same way they have been attached.
|
|
30
|
+
// Since the handler functions have variables that change after hot-reload, keep them exactly
|
|
31
|
+
// as is in an array so we can delete them on destroy.
|
|
32
|
+
// This only applies to the activatorEventHandlers, the other events listeners can be removed
|
|
33
|
+
// normally.
|
|
34
|
+
docAEventListenersHandlers: []
|
|
35
|
+
}),
|
|
36
|
+
|
|
10
37
|
computed: {
|
|
11
38
|
// DOM element to attach tooltip/menu to.
|
|
12
39
|
// ! \ This computed uses the DOM - NO SSR (only trigger from beforeMount and later).
|
|
@@ -40,6 +67,40 @@ export default {
|
|
|
40
67
|
// ! \ This computed uses the DOM - NO SSR (only trigger from beforeMount and later).
|
|
41
68
|
detachableParentEl () {
|
|
42
69
|
return this.appendToTarget
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
hasSeparateActivator () {
|
|
73
|
+
return !this.$scopedSlots.activator && typeof this.activator === 'string'
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
activatorEl: {
|
|
77
|
+
get () {
|
|
78
|
+
if (this.hasSeparateActivator) return document.querySelector(this.activator)
|
|
79
|
+
return this.$el.firstElementChild
|
|
80
|
+
},
|
|
81
|
+
set () {
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
position () {
|
|
87
|
+
return (
|
|
88
|
+
(this.top && 'top') ||
|
|
89
|
+
(this.bottom && 'bottom') ||
|
|
90
|
+
(this.left && 'left') ||
|
|
91
|
+
(this.right && 'right') ||
|
|
92
|
+
'bottom'
|
|
93
|
+
)
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
alignment () {
|
|
97
|
+
return (
|
|
98
|
+
(['top', 'bottom'].includes(this.position) && this.alignLeft && 'left') ||
|
|
99
|
+
(['top', 'bottom'].includes(this.position) && this.alignRight && 'right') ||
|
|
100
|
+
(['left', 'right'].includes(this.position) && this.alignTop && 'top') ||
|
|
101
|
+
(['left', 'right'].includes(this.position) && this.alignBottom && 'bottom') ||
|
|
102
|
+
''
|
|
103
|
+
)
|
|
43
104
|
}
|
|
44
105
|
},
|
|
45
106
|
|
|
@@ -176,14 +237,85 @@ export default {
|
|
|
176
237
|
|
|
177
238
|
// Move the tooltip/menu elsewhere in the DOM.
|
|
178
239
|
// wrapper.parentNode.insertBefore(this.detachableEl, wrapper)
|
|
179
|
-
this.appendToTarget.appendChild(this.detachableEl)
|
|
240
|
+
if (this.detachableEl) this.appendToTarget.appendChild(this.detachableEl)
|
|
180
241
|
resolve()
|
|
181
242
|
})
|
|
182
243
|
})
|
|
183
244
|
},
|
|
184
245
|
|
|
185
246
|
removeFromDOM () {
|
|
186
|
-
|
|
247
|
+
document.removeEventListener('mousedown', this.onOutsideMousedown)
|
|
248
|
+
window.removeEventListener('resize', this.onResize)
|
|
249
|
+
if (this.detachableEl && this.detachableEl.parentNode) {
|
|
250
|
+
this.detachableVisible = false
|
|
251
|
+
this.detachableEl.remove()
|
|
252
|
+
this.detachableEl = null
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
mounted () {
|
|
258
|
+
const wrapper = this.$el
|
|
259
|
+
|
|
260
|
+
// Unwrap the activator element if the activator is in the activator slot.
|
|
261
|
+
if (this.$scopedSlots.activator) wrapper.parentNode.insertBefore(this.activatorEl, wrapper)
|
|
262
|
+
|
|
263
|
+
// If the activator is external, add event listeners to the document and check the target is
|
|
264
|
+
// the activator when toggling.
|
|
265
|
+
// This way, the activator can be a future DOM element, that is not yet in the DOM.
|
|
266
|
+
else if (this.activator) {
|
|
267
|
+
Object.entries(this.activatorEventHandlers).forEach(([eventName, handler]) => {
|
|
268
|
+
// Convert mouseenter to mouseover & mouseleave to mouseout because we are attaching
|
|
269
|
+
// event to the document, so it can accept future nodes.
|
|
270
|
+
eventName = eventName.replace('mouseenter', 'mouseover').replace('mouseleave', 'mouseout')
|
|
271
|
+
const handlerWrap = e => {
|
|
272
|
+
if (e.target?.matches && e.target.matches(this.activator)) handler(e)
|
|
273
|
+
}
|
|
274
|
+
document.addEventListener(eventName, handlerWrap)
|
|
275
|
+
// The event listeners handlers have to be removed the exact same way they have been attached.
|
|
276
|
+
// Since the handler functions have variables that change after hot-reload, keep them exactly
|
|
277
|
+
// as is in an array so we can delete them on destroy.
|
|
278
|
+
this.docAEventListenersHandlers.push({ eventName, handler: handlerWrap })
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Unwrap the overlay if any.
|
|
283
|
+
if (this.overlay) {
|
|
284
|
+
this.overlayEl = this.$refs.overlay?.$el
|
|
285
|
+
wrapper.parentNode.insertBefore(this.overlayEl, wrapper)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (this.value) this.toggleMenu({ type: 'click', target: this.activatorEl })
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
beforeDestroy () {
|
|
292
|
+
this.close()
|
|
293
|
+
|
|
294
|
+
this.removeFromDOM()
|
|
295
|
+
|
|
296
|
+
// Remove the event listeners the exact same way they have been defined.
|
|
297
|
+
// Fixes issues on hot-reloading.
|
|
298
|
+
if (this.docAEventListenersHandlers.length) {
|
|
299
|
+
this.docAEventListenersHandlers.forEach(({ eventName, handler }) => {
|
|
300
|
+
document.removeEventListener(eventName, handler)
|
|
301
|
+
})
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (this.overlay && this.overlayEl.parentNode) this.overlayEl.remove()
|
|
305
|
+
if (this.activatorEl?.parentNode && this.$scopedSlots.activator) this.activatorEl.remove()
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
watch: {
|
|
309
|
+
value (bool) {
|
|
310
|
+
if (!!bool !== this.detachableVisible) this.toggle({ type: 'click', target: this.activatorEl })
|
|
311
|
+
},
|
|
312
|
+
detachTo () {
|
|
313
|
+
this.removeFromDOM()
|
|
314
|
+
this.insertInDOM()
|
|
315
|
+
},
|
|
316
|
+
appendTo () {
|
|
317
|
+
this.removeFromDOM()
|
|
318
|
+
this.insertInDOM()
|
|
187
319
|
}
|
|
188
320
|
}
|
|
189
321
|
}
|