wave-ui 3.25.6 → 3.26.1

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 (111) hide show
  1. package/dist/types/{components → types/components}/WAccordion.d.ts +18 -0
  2. package/dist/types/{components → types/components}/WMenu.d.ts +6 -0
  3. package/dist/types/{components → types/components}/WTooltip.d.ts +6 -0
  4. package/dist/types/{plugin.d.ts → types/plugin.d.ts} +0 -1
  5. package/dist/wave-ui.cjs.js +4 -1
  6. package/dist/wave-ui.css +2 -1
  7. package/dist/wave-ui.esm.js +8964 -0
  8. package/dist/wave-ui.umd.js +4 -1
  9. package/package.json +22 -22
  10. package/src/wave-ui/components/w-accordion/accordion-content.vue +14 -0
  11. package/src/wave-ui/components/w-accordion/index.vue +3 -1
  12. package/src/wave-ui/components/w-accordion/item.vue +31 -2
  13. package/src/wave-ui/components/w-confirm.vue +17 -1
  14. package/src/wave-ui/components/w-menu.vue +20 -11
  15. package/src/wave-ui/components/w-tooltip.vue +23 -12
  16. package/src/wave-ui/core.js +1 -4
  17. package/src/wave-ui/index.d.ts +0 -2
  18. package/src/wave-ui/mixins/detachable.js +167 -86
  19. package/dist/wave-ui.es.js +0 -8429
  20. /package/dist/types/{$waveui.d.ts → types/$waveui.d.ts} +0 -0
  21. /package/dist/types/{$waveui.js → types/$waveui.js} +0 -0
  22. /package/dist/types/{colors.d.ts → types/colors.d.ts} +0 -0
  23. /package/dist/types/{colors.js → types/colors.js} +0 -0
  24. /package/dist/types/{components → types/components}/WAccordion.js +0 -0
  25. /package/dist/types/{components → types/components}/WAlert.d.ts +0 -0
  26. /package/dist/types/{components → types/components}/WAlert.js +0 -0
  27. /package/dist/types/{components → types/components}/WApp.d.ts +0 -0
  28. /package/dist/types/{components → types/components}/WApp.js +0 -0
  29. /package/dist/types/{components → types/components}/WBadge.d.ts +0 -0
  30. /package/dist/types/{components → types/components}/WBadge.js +0 -0
  31. /package/dist/types/{components → types/components}/WBreadcrumbs.d.ts +0 -0
  32. /package/dist/types/{components → types/components}/WBreadcrumbs.js +0 -0
  33. /package/dist/types/{components → types/components}/WButton.d.ts +0 -0
  34. /package/dist/types/{components → types/components}/WButton.js +0 -0
  35. /package/dist/types/{components → types/components}/WCard.d.ts +0 -0
  36. /package/dist/types/{components → types/components}/WCard.js +0 -0
  37. /package/dist/types/{components → types/components}/WCheckbox.d.ts +0 -0
  38. /package/dist/types/{components → types/components}/WCheckbox.js +0 -0
  39. /package/dist/types/{components → types/components}/WCheckboxes.d.ts +0 -0
  40. /package/dist/types/{components → types/components}/WCheckboxes.js +0 -0
  41. /package/dist/types/{components → types/components}/WConfirm.d.ts +0 -0
  42. /package/dist/types/{components → types/components}/WConfirm.js +0 -0
  43. /package/dist/types/{components → types/components}/WDialog.d.ts +0 -0
  44. /package/dist/types/{components → types/components}/WDialog.js +0 -0
  45. /package/dist/types/{components → types/components}/WDivider.d.ts +0 -0
  46. /package/dist/types/{components → types/components}/WDivider.js +0 -0
  47. /package/dist/types/{components → types/components}/WDrawer.d.ts +0 -0
  48. /package/dist/types/{components → types/components}/WDrawer.js +0 -0
  49. /package/dist/types/{components → types/components}/WFlex.d.ts +0 -0
  50. /package/dist/types/{components → types/components}/WFlex.js +0 -0
  51. /package/dist/types/{components → types/components}/WForm.d.ts +0 -0
  52. /package/dist/types/{components → types/components}/WForm.js +0 -0
  53. /package/dist/types/{components → types/components}/WFormElement.d.ts +0 -0
  54. /package/dist/types/{components → types/components}/WFormElement.js +0 -0
  55. /package/dist/types/{components → types/components}/WGrid.d.ts +0 -0
  56. /package/dist/types/{components → types/components}/WGrid.js +0 -0
  57. /package/dist/types/{components → types/components}/WIcon.d.ts +0 -0
  58. /package/dist/types/{components → types/components}/WIcon.js +0 -0
  59. /package/dist/types/{components → types/components}/WImage.d.ts +0 -0
  60. /package/dist/types/{components → types/components}/WImage.js +0 -0
  61. /package/dist/types/{components → types/components}/WInput.d.ts +0 -0
  62. /package/dist/types/{components → types/components}/WInput.js +0 -0
  63. /package/dist/types/{components → types/components}/WList.d.ts +0 -0
  64. /package/dist/types/{components → types/components}/WList.js +0 -0
  65. /package/dist/types/{components → types/components}/WMenu.js +0 -0
  66. /package/dist/types/{components → types/components}/WNotification.d.ts +0 -0
  67. /package/dist/types/{components → types/components}/WNotification.js +0 -0
  68. /package/dist/types/{components → types/components}/WNotificationManager.d.ts +0 -0
  69. /package/dist/types/{components → types/components}/WNotificationManager.js +0 -0
  70. /package/dist/types/{components → types/components}/WOverlay.d.ts +0 -0
  71. /package/dist/types/{components → types/components}/WOverlay.js +0 -0
  72. /package/dist/types/{components → types/components}/WProgress.d.ts +0 -0
  73. /package/dist/types/{components → types/components}/WProgress.js +0 -0
  74. /package/dist/types/{components → types/components}/WRadio.d.ts +0 -0
  75. /package/dist/types/{components → types/components}/WRadio.js +0 -0
  76. /package/dist/types/{components → types/components}/WRadios.d.ts +0 -0
  77. /package/dist/types/{components → types/components}/WRadios.js +0 -0
  78. /package/dist/types/{components → types/components}/WRating.d.ts +0 -0
  79. /package/dist/types/{components → types/components}/WRating.js +0 -0
  80. /package/dist/types/{components → types/components}/WSelect.d.ts +0 -0
  81. /package/dist/types/{components → types/components}/WSelect.js +0 -0
  82. /package/dist/types/{components → types/components}/WSlider.d.ts +0 -0
  83. /package/dist/types/{components → types/components}/WSlider.js +0 -0
  84. /package/dist/types/{components → types/components}/WSpinner.d.ts +0 -0
  85. /package/dist/types/{components → types/components}/WSpinner.js +0 -0
  86. /package/dist/types/{components → types/components}/WSteps.d.ts +0 -0
  87. /package/dist/types/{components → types/components}/WSteps.js +0 -0
  88. /package/dist/types/{components → types/components}/WSwitch.d.ts +0 -0
  89. /package/dist/types/{components → types/components}/WSwitch.js +0 -0
  90. /package/dist/types/{components → types/components}/WTable.d.ts +0 -0
  91. /package/dist/types/{components → types/components}/WTable.js +0 -0
  92. /package/dist/types/{components → types/components}/WTabs.d.ts +0 -0
  93. /package/dist/types/{components → types/components}/WTabs.js +0 -0
  94. /package/dist/types/{components → types/components}/WTag.d.ts +0 -0
  95. /package/dist/types/{components → types/components}/WTag.js +0 -0
  96. /package/dist/types/{components → types/components}/WTextarea.d.ts +0 -0
  97. /package/dist/types/{components → types/components}/WTextarea.js +0 -0
  98. /package/dist/types/{components → types/components}/WTimeline.d.ts +0 -0
  99. /package/dist/types/{components → types/components}/WTimeline.js +0 -0
  100. /package/dist/types/{components → types/components}/WToolbar.d.ts +0 -0
  101. /package/dist/types/{components → types/components}/WToolbar.js +0 -0
  102. /package/dist/types/{components → types/components}/WTooltip.js +0 -0
  103. /package/dist/types/{components → types/components}/WTree.d.ts +0 -0
  104. /package/dist/types/{components → types/components}/WTree.js +0 -0
  105. /package/dist/types/{components → types/components}/index.d.ts +0 -0
  106. /package/dist/types/{components → types/components}/index.js +0 -0
  107. /package/dist/types/{extra-vue-types.d.ts → types/extra-vue-types.d.ts} +0 -0
  108. /package/dist/types/{extra-vue-types.js → types/extra-vue-types.js} +0 -0
  109. /package/dist/types/{index.d.ts → types/index.d.ts} +0 -0
  110. /package/dist/types/{index.js → types/index.js} +0 -0
  111. /package/dist/types/{plugin.js → types/plugin.js} +0 -0
@@ -6,6 +6,13 @@
6
6
 
7
7
  import { consoleWarn } from '../utils/console'
8
8
 
9
+ // Minimum space (px) from the viewport edge when flipping / nudging.
10
+ const VIEWPORT_MARGIN = 4
11
+
12
+ function oppositePlacement (side) {
13
+ return { top: 'bottom', bottom: 'top', left: 'right', right: 'left' }[side] || 'bottom'
14
+ }
15
+
9
16
  export default {
10
17
  props: {
11
18
  // Position.
@@ -23,7 +30,9 @@ export default {
23
30
  zIndex: { type: [Number, String, Boolean] },
24
31
  // Optionally designate an external activator.
25
32
  // The activator can be a DOM string selector, a ref or a DOM node.
26
- activator: { type: [String, Object] }
33
+ activator: { type: [String, Object] },
34
+ // When true, the tooltip/menu does not open; the activator stays in the DOM.
35
+ disable: { type: Boolean, default: false }
27
36
  },
28
37
 
29
38
  inject: {
@@ -40,13 +49,21 @@ export default {
40
49
  // The user may open and close the detachable so fast (like when toggling on hover) that it
41
50
  // should not show up at all. Keep the ability to cancel the opening timer (if there is a set
42
51
  // delay prop).
43
- openTimeout: null
52
+ openTimeout: null,
53
+ // When set, overrides `position` for CSS (arrow / slide direction) after viewport auto-flip.
54
+ viewportPlacementOverride: null,
55
+ // Set to true by computeDetachableCoords after positioning, false until then.
56
+ // Components use this to bind visibility:hidden, so the element is never visible at the
57
+ // wrong position before its coordinates are calculated.
58
+ detachableReady: false
44
59
  }),
45
60
 
46
61
  computed: {
47
62
  // DOM element to attach tooltip/menu to.
48
63
  // ! \ This computed uses the DOM - NO SSR (only trigger from beforeMount and later).
49
64
  appendToTarget () {
65
+ if (typeof document === 'undefined') return null
66
+
50
67
  let defaultTarget = '.w-app'
51
68
 
52
69
  // If used inside a w-dialog, w-drawer, or w-menu without an appendTo, default to that open
@@ -91,6 +108,7 @@ export default {
91
108
  if (this.hasSeparateActivator) {
92
109
  const activator = this.activator?.$el || this.activator
93
110
  if (activator instanceof HTMLElement) return activator
111
+ if (typeof document === 'undefined') return null
94
112
  return document.querySelector(this.activator)
95
113
  }
96
114
  return this.$el.nextElementSibling
@@ -123,12 +141,35 @@ export default {
123
141
  // whereas the w-menu has `showOnClick`.
124
142
  return (this.$options.props.showOnHover && !this.showOnHover) ||
125
143
  (this.$options.props.showOnClick && this.showOnClick)
144
+ },
145
+
146
+ /** Placement used for CSS classes (arrows, margins); reflects viewport flip when applied. */
147
+ effectiveDetachablePosition () {
148
+ return this.viewportPlacementOverride || this.position
126
149
  }
127
150
  },
128
151
 
129
152
  methods: {
153
+ // Called by <transition @after-leave>. Resets detachableReady after the leave animation so the
154
+ // next open starts hidden. Done here rather than on close() to let the leave animation play.
155
+ onAfterLeave () {
156
+ this.detachableReady = false
157
+ },
158
+
159
+ unbindActivatorDocEvents () {
160
+ if (typeof document === 'undefined') return
161
+ if (this.docEventListenersHandlers.length) {
162
+ this.docEventListenersHandlers.forEach(({ eventName, handler }) => {
163
+ document.removeEventListener(eventName, handler)
164
+ })
165
+ this.docEventListenersHandlers = []
166
+ }
167
+ },
168
+
130
169
  // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
131
170
  async open (e) {
171
+ if (this.disable) return
172
+
132
173
  // A tiny delay may help positioning the detachable correctly in case of multiple activators
133
174
  // with different menu contents.
134
175
  if (this.delay) await new Promise(resolve => (this.openTimeout = setTimeout(resolve, this.delay)))
@@ -136,6 +177,10 @@ export default {
136
177
  // Cancel opening if the timeout has been cancelled by blur event (when going fast).
137
178
  if (this.delay && !this.openTimeout) return
138
179
 
180
+ if (this.disable) return
181
+
182
+ // Hide before entering the DOM; handles rapid re-opens where detachableReady is still true.
183
+ this.detachableReady = false
139
184
  this.detachableVisible = true
140
185
 
141
186
  // If the activator is external, there might be multiple,
@@ -144,9 +189,12 @@ export default {
144
189
 
145
190
  await this.insertInDOM()
146
191
 
147
- if (this.minWidth === 'activator') this.activatorWidth = this.activatorEl.offsetWidth
192
+ if (this.minWidth === 'activator' && this.activatorEl) {
193
+ this.activatorWidth = this.activatorEl.offsetWidth
194
+ }
148
195
 
149
196
  if (!this.noPosition) this.computeDetachableCoords()
197
+ else this.detachableReady = true
150
198
 
151
199
  // In `getActivatorCoordinates` accessing the menu computed styles takes a few ms (less than 10ms),
152
200
  // if we don't postpone the Menu apparition it will start transition from a visible menu and
@@ -157,12 +205,20 @@ export default {
157
205
  this.$emit('open')
158
206
  }, 0)
159
207
 
160
- if (!this.persistent) document.addEventListener('mousedown', this.onOutsideMousedown)
161
- if (!this.noPosition) window.addEventListener('resize', this.onResize)
208
+ if (typeof document !== 'undefined' && !this.persistent) {
209
+ document.addEventListener('mousedown', this.onOutsideMousedown)
210
+ }
211
+ if (typeof window !== 'undefined' && !this.noPosition) {
212
+ window.addEventListener('resize', this.onResize)
213
+ }
162
214
  },
163
215
 
164
216
  // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
165
217
  getActivatorCoordinates () {
218
+ if (typeof window === 'undefined' || typeof document === 'undefined' || !this.activatorEl || !this.detachableParentEl) {
219
+ return { top: 0, left: 0, width: 0, height: 0 }
220
+ }
221
+
166
222
  // Get the activator coordinates relative to window.
167
223
  const { top, left, width, height } = this.activatorEl.getBoundingClientRect()
168
224
  let coords = { top, left, width, height }
@@ -181,113 +237,127 @@ export default {
181
237
  return coords
182
238
  },
183
239
 
184
- // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
185
- computeDetachableCoords () {
186
- // Get the activator coordinates.
187
- let { top, left, width, height } = this.getActivatorCoordinates()
240
+ /**
241
+ * Apply `placement` (top | bottom | left | right) to activator-relative coords.
242
+ * @returns {{ top: number, left: number }}
243
+ */
244
+ _applyDetachablePlacement (placement, baseCoords, computedStyles) {
245
+ let { top, left, width, height } = baseCoords
246
+ const el = this.detachableEl
188
247
 
189
- // Prevent error in case the detachable component unmounted hook is fired but the activator
190
- // is still in the DOM until the end of a transition and the user toggles it.
191
- // Unmounted is called straight away from beforeLeave: https://github.com/vuejs/core/issues/994
192
- if (!this.detachableEl) return
193
-
194
- // 1. First display the menu but hide it (So we can get its dimension).
195
- // --------------------------------------------------
196
- this.detachableEl.style.visibility = 'hidden'
197
- this.detachableEl.style.display = 'flex'
198
- const computedStyles = window.getComputedStyle(this.detachableEl, null)
199
-
200
- // 2. Position the menu top, left, right, bottom and apply chosen alignment.
201
- // --------------------------------------------------
202
- // Subtract half or full activator width or height and menu width or height according to the
203
- // menu alignment.
204
- // Note: the menu position relies on transform translate, the custom animation may override the
205
- // css transform property so do without it i.e. no translateX(-50%), and recalculate top & left
206
- // manually.
207
- switch (this.position) {
248
+ switch (placement) {
208
249
  case 'top': {
209
- top -= this.detachableEl.offsetHeight
250
+ top -= el.offsetHeight
210
251
  if (this.alignRight) {
211
- // left: 100% of activator.
212
- left += width - this.detachableEl.offsetWidth +
213
- parseInt(computedStyles.getPropertyValue('border-right-width'))
252
+ left += width - el.offsetWidth +
253
+ parseInt(computedStyles.getPropertyValue('border-right-width'), 10)
214
254
  }
215
- else if (!this.alignLeft) left += (width - this.detachableEl.offsetWidth) / 2 // left: 50% of activator - half menu width.
255
+ else if (!this.alignLeft) left += (width - el.offsetWidth) / 2
216
256
  break
217
257
  }
218
258
  case 'bottom': {
219
259
  top += height
220
260
  if (this.alignRight) {
221
- // left: 100% of activator.
222
- left += width - this.detachableEl.offsetWidth +
223
- parseInt(computedStyles.getPropertyValue('border-right-width'))
261
+ left += width - el.offsetWidth +
262
+ parseInt(computedStyles.getPropertyValue('border-right-width'), 10)
224
263
  }
225
- else if (!this.alignLeft) left += (width - this.detachableEl.offsetWidth) / 2 // left: 50% of activator - half menu width.
264
+ else if (!this.alignLeft) left += (width - el.offsetWidth) / 2
226
265
  break
227
266
  }
228
267
  case 'left': {
229
- left -= this.detachableEl.offsetWidth
230
- if (this.alignBottom) top += height - this.detachableEl.offsetHeight
231
- else if (!this.alignTop) top += (height - this.detachableEl.offsetHeight) / 2 // top: 50% of activator - half menu height.
268
+ left -= el.offsetWidth
269
+ if (this.alignBottom) top += height - el.offsetHeight
270
+ else if (!this.alignTop) top += (height - el.offsetHeight) / 2
232
271
  break
233
272
  }
234
273
  case 'right': {
235
274
  left += width
236
275
  if (this.alignBottom) {
237
- top += height - this.detachableEl.offsetHeight +
238
- parseInt(computedStyles.getPropertyValue('margin-top'))
276
+ top += height - el.offsetHeight +
277
+ parseInt(computedStyles.getPropertyValue('margin-top'), 10)
239
278
  }
240
279
  else if (!this.alignTop) {
241
- top += (height - this.detachableEl.offsetHeight) / 2 + // top: 50% of activator - half menu height.
242
- parseInt(computedStyles.getPropertyValue('margin-top'))
280
+ top += (height - el.offsetHeight) / 2 +
281
+ parseInt(computedStyles.getPropertyValue('margin-top'), 10)
243
282
  }
244
283
  break
245
284
  }
246
285
  }
286
+ return { top, left }
287
+ },
247
288
 
248
- // 3. Keep fully in viewport.
249
- // @todo: do this.
250
- // --------------------------------------------------
251
- // if (this.position === 'top' && ((top - this.detachableEl.offsetHeight) < 0)) {
252
- // const margin = - parseInt(computedStyles.getPropertyValue('margin-top'))
253
- // top -= top - this.detachableEl.offsetHeight - margin - marginFromWindowSide
254
- // }
255
- // else if (this.position === 'left' && left - this.detachableEl.offsetWidth < 0) {
256
- // const margin = - parseInt(computedStyles.getPropertyValue('margin-left'))
257
- // left -= left - this.detachableEl.offsetWidth - margin - marginFromWindowSide
258
- // }
259
- // else if (this.position === 'right' && left + width + this.detachableEl.offsetWidth > window.innerWidth) {
260
- // const margin = parseInt(computedStyles.getPropertyValue('margin-left'))
261
- // left -= left + width + this.detachableEl.offsetWidth - window.innerWidth + margin + marginFromWindowSide
262
- // }
263
- // else if (this.position === 'bottom' && top + height + this.detachableEl.offsetHeight > window.innerHeight) {
264
- // const margin = parseInt(computedStyles.getPropertyValue('margin-top'))
265
- // top -= top + height + this.detachableEl.offsetHeight - window.innerHeight + margin + marginFromWindowSide
266
- // }
267
-
268
- // 4. Hide the menu again so the transition happens correctly.
269
- // --------------------------------------------------
270
- this.detachableEl.style.visibility = null
271
-
272
- // The menu coordinates are also recalculated while resizing window with open menu: keep the menu visible.
273
- if (!this.detachableVisible) this.detachableEl.style.display = 'none'
289
+ // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
290
+ async computeDetachableCoords () {
291
+ if (typeof window === 'undefined' || !this.detachableEl) return
292
+
293
+ // Prevent error in case the detachable component unmounted hook is fired but the activator
294
+ // is still in the DOM until the end of a transition and the user toggles it.
295
+ // Unmounted is called straight away from beforeLeave: https://github.com/vuejs/core/issues/994
296
+ if (!this.activatorEl || !this.detachableParentEl) return
297
+
298
+ this.viewportPlacementOverride = null
299
+
300
+ // Measure the element (already hidden via visibility:hidden in the component :style).
301
+ this.detachableEl.style.display = 'flex'
302
+ const computedStyles = window.getComputedStyle(this.detachableEl, null)
303
+ const elW = this.detachableEl.offsetWidth
304
+ const elH = this.detachableEl.offsetHeight
305
+
306
+ // Flip to the opposite side if the element won't fit pure arithmetic on the viewport rect.
307
+ let placement = this.position
308
+ if (!this.noPosition) {
309
+ const m = VIEWPORT_MARGIN
310
+ const vw = window.innerWidth
311
+ const vh = window.innerHeight
312
+ const { top: aTop, left: aLeft, width: aW, height: aH } = this.activatorEl.getBoundingClientRect()
313
+
314
+ if (
315
+ (placement === 'bottom' && aTop + aH + elH > vh - m && aTop - elH >= m) ||
316
+ (placement === 'top' && aTop - elH < m && aTop + aH + elH <= vh - m) ||
317
+ (placement === 'right' && aLeft + aW + elW > vw - m && aLeft - elW >= m) ||
318
+ (placement === 'left' && aLeft - elW < m && aLeft + aW + elW <= vw - m)
319
+ ) {
320
+ placement = oppositePlacement(placement)
321
+ this.viewportPlacementOverride = placement
322
+ }
323
+ }
324
+
325
+ // Compute the parent-relative top/left for the chosen placement.
326
+ const baseCoords = this.getActivatorCoordinates()
327
+ const { top, left } = this._applyDetachablePlacement(placement, baseCoords, computedStyles)
274
328
 
275
329
  this.detachableCoords = { top, left }
330
+ // Reveal: detachableReady = true makes the :style binding clear visibility:hidden.
331
+ // Always await $nextTick so coordinates, placement class, and visibility are flushed atomically.
332
+ this.detachableReady = true
333
+ await this.$nextTick()
334
+
335
+ // Guard against the component being unmounted while awaiting.
336
+ if (!this.detachableEl) return
337
+ if (!this.detachableVisible) this.detachableEl.style.display = 'none'
276
338
  },
277
339
 
278
340
  onResize () {
279
- if (this.minWidth === 'activator') this.activatorWidth = this.activatorEl.offsetWidth
341
+ if (typeof window === 'undefined') return
342
+ if (this.minWidth === 'activator' && this.activatorEl) {
343
+ this.activatorWidth = this.activatorEl.offsetWidth
344
+ }
280
345
  this.computeDetachableCoords()
281
346
  },
282
347
 
283
348
  // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
284
349
  onOutsideMousedown (e) {
350
+ if (!this.detachableEl || !this.activatorEl) return
285
351
  if (!this.detachableEl.contains(e.target) && !this.activatorEl.contains(e.target)) {
286
352
  this.$emit('update:modelValue', (this.detachableVisible = false))
287
353
  this.$emit('input', false)
288
354
  this.$emit('close')
289
- document.removeEventListener('mousedown', this.onOutsideMousedown)
290
- window.removeEventListener('resize', this.onResize)
355
+ if (typeof document !== 'undefined') {
356
+ document.removeEventListener('mousedown', this.onOutsideMousedown)
357
+ }
358
+ if (typeof window !== 'undefined') {
359
+ window.removeEventListener('resize', this.onResize)
360
+ }
291
361
  }
292
362
  },
293
363
 
@@ -297,15 +367,19 @@ export default {
297
367
  this.detachableEl = this.$refs.detachable?.$el || this.$refs.detachable
298
368
 
299
369
  // Move the tooltip/menu elsewhere in the DOM.
300
- if (this.detachableEl) this.appendToTarget.appendChild(this.detachableEl)
370
+ if (this.detachableEl && this.appendToTarget) this.appendToTarget.appendChild(this.detachableEl)
301
371
  resolve()
302
372
  })
303
373
  })
304
374
  },
305
375
 
306
376
  removeFromDOM () {
307
- document.removeEventListener('mousedown', this.onOutsideMousedown)
308
- window.removeEventListener('resize', this.onResize)
377
+ if (typeof document !== 'undefined') {
378
+ document.removeEventListener('mousedown', this.onOutsideMousedown)
379
+ }
380
+ if (typeof window !== 'undefined') {
381
+ window.removeEventListener('resize', this.onResize)
382
+ }
309
383
  if (this.detachableEl?.parentNode) {
310
384
  this.detachableVisible = false
311
385
  this.detachableEl.remove()
@@ -317,6 +391,8 @@ export default {
317
391
  // the activator when toggling.
318
392
  // This way, the activator can be a future DOM element, that is not yet in the DOM.
319
393
  bindActivatorEvents () {
394
+ if (typeof document === 'undefined') return
395
+
320
396
  const activatorIsString = typeof this.activator === 'string'
321
397
 
322
398
  Object.entries(this.activatorEventHandlers).forEach(([eventName, handler]) => {
@@ -346,17 +422,17 @@ export default {
346
422
  else {
347
423
  this.$nextTick(() => {
348
424
  if (this.activator) this.bindActivatorEvents()
349
- if (this.modelValue) this.open({ target: this.activatorEl })
425
+ if (this.modelValue && !this.disable) this.open({ target: this.activatorEl })
350
426
  })
351
427
  }
352
428
 
353
429
  // Unwrap the overlay if any.
354
430
  if (this.overlay) this.overlayEl = this.$refs.overlay?.$el
355
431
 
356
- if (this.modelValue && this.activator) {
432
+ if (this.modelValue && this.activator && !this.disable) {
357
433
  this.toggle({ type: this.shouldShowOnClick ? 'click' : 'mouseenter', target: this.activatorEl })
358
434
  }
359
- else if (this.modelValue) this.open({ target: this.activatorEl })
435
+ else if (this.modelValue && !this.disable) this.open({ target: this.activatorEl })
360
436
  },
361
437
 
362
438
  unmounted () {
@@ -366,18 +442,23 @@ export default {
366
442
 
367
443
  // Remove the event listeners the exact same way they have been defined.
368
444
  // Fixes issues on hot-reloading.
369
- if (this.docEventListenersHandlers.length) {
370
- this.docEventListenersHandlers.forEach(({ eventName, handler }) => {
371
- document.removeEventListener(eventName, handler)
372
- })
373
- }
445
+ this.unbindActivatorDocEvents()
374
446
  },
375
447
 
376
448
  watch: {
449
+ disable (disabled) {
450
+ if (this.activator) {
451
+ this.unbindActivatorDocEvents()
452
+ if (!disabled) this.bindActivatorEvents()
453
+ }
454
+ if (disabled) this.close()
455
+ else if (this.modelValue) this.open({ target: this.activatorEl })
456
+ },
457
+
377
458
  modelValue (bool) {
378
459
  if (!!bool !== this.detachableVisible) {
379
- if (bool) this.open({ target: this.activatorEl })
380
- else this.close()
460
+ if (bool && !this.disable) this.open({ target: this.activatorEl })
461
+ else if (!bool) this.close()
381
462
  }
382
463
  },
383
464
  appendTo () {