Skip to content

Commit

Permalink
fix(vue3): do not rely on __vueParentComponent in tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
xanf committed Oct 24, 2022
1 parent d8edafc commit fe13503
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 14 deletions.
7 changes: 4 additions & 3 deletions src/components/link/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { isBoolean, isEvent, isFunction, isUndefined } from '../../utils/inspect
import { omit, sortKeys } from '../../utils/object'
import { makeProp, makePropsConfigurable, pluckProps } from '../../utils/props'
import { computeHref, computeRel, computeTag, isRouterLink } from '../../utils/router'
import { getInstanceFromVNode } from '../../utils/get-instance-from-vnode'
import { attrsMixin } from '../../mixins/attrs'
import { listenOnRootMixin } from '../../mixins/listen-on-root'
import { listenersMixin } from '../../mixins/listeners'
Expand Down Expand Up @@ -165,9 +164,11 @@ export const BLink = /*#__PURE__*/ Vue.extend({
} else {
// Router links do not emit instance `click` events, so we
// add in an `$emit('click', event)` on its Vue instance
//
// seems not to be required for Vue3 compat build
/* istanbul ignore next: difficult to test, but we know it works */
if (isRouterLink && getInstanceFromVNode(event.currentTarget)) {
getInstanceFromVNode(event.currentTarget).$emit(EVENT_NAME_CLICK, event)
if (isRouterLink) {
event.currentTarget.__vue__?.$emit(EVENT_NAME_CLICK, event)
}
// Call the suppliedHandler(s), if any provided
concat(suppliedHandler)
Expand Down
3 changes: 1 addition & 2 deletions src/components/modal/modal.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createWrapper, mount } from '@vue/test-utils'
import { isVue3 } from '../../vue'
import { waitNT, waitRAF } from '../../../tests/utils'
import { getInstanceFromVNode } from '../../utils/get-instance-from-vnode'
import { waitNT, waitRAF, getInstanceFromVNode } from '../../../tests/utils'
import { BModal } from './modal'
import { BvModalEvent } from './helpers/bv-modal-event.class'

Expand Down
8 changes: 5 additions & 3 deletions src/components/tooltip/helpers/bv-tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from '../../../constants/events'
import { useParentMixin } from '../../../mixins/use-parent'
import { arrayIncludes, concat, from as arrayFrom } from '../../../utils/array'
import { getInstanceFromVNode } from '../../../utils/get-instance-from-vnode'
import { getInstanceFromElement } from '../../../utils/element-to-vue-instance-registry'
import {
attemptFocus,
closest,
Expand Down Expand Up @@ -796,8 +796,10 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
// Dropdown shown and hidden events will need to emit
// Note: Dropdown auto-ID happens in a `$nextTick()` after mount
// So the ID lookup would need to be done in a `$nextTick()`
if (getInstanceFromVNode(target)) {
getInstanceFromVNode(target)[on ? '$on' : '$off'](EVENT_NAME_SHOWN, this.forceHide)
const instance = getInstanceFromElement(target)

if (instance) {
instance[on ? '$on' : '$off'](EVENT_NAME_SHOWN, this.forceHide)
}
},
// --- Event handlers ---
Expand Down
3 changes: 1 addition & 2 deletions src/components/transporter/transporter.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { isVue3 } from '../../vue'
import { mount } from '@vue/test-utils'
import { waitNT } from '../../../tests/utils'
import { getInstanceFromVNode } from '../../utils/get-instance-from-vnode'
import { waitNT, getInstanceFromVNode } from '../../../tests/utils'
import { BVTransporter } from './transporter'

describe('utils/transporter component', () => {
Expand Down
8 changes: 8 additions & 0 deletions src/mixins/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ import { clickOutMixin } from './click-out'
import { focusInMixin } from './focus-in'
import { idMixin, props as idProps } from './id'
import { listenOnRootMixin } from './listen-on-root'
import {
registerElementToInstance,
removeElementToInstance
} from '../utils/element-to-vue-instance-registry'

// --- Constants ---

Expand Down Expand Up @@ -181,11 +185,15 @@ export const dropdownMixin = Vue.extend({
this.whileOpenListen(false)
this.destroyPopper()
},
mounted() {
registerElementToInstance(this.$el, this)
},
beforeDestroy() {
this.visible = false
this.whileOpenListen(false)
this.destroyPopper()
this.clearHideTimeout()
removeElementToInstance(this.$el)
},
methods: {
// Event emitter
Expand Down
39 changes: 39 additions & 0 deletions src/utils/element-to-vue-instance-registry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { isVue3 } from '../vue'

let registry = null
if (isVue3) {
registry = new WeakMap()
}

export const registerElementToInstance = (element, instance) => {
if (!isVue3) {
return
}

registry.set(element, instance)
}

export const removeElementToInstance = element => {
if (!isVue3) {
return
}

registry.delete(element)
}

export const getInstanceFromElement = element => {
if (!isVue3) {
return element.__vue__
}

let currentElement = element

while (currentElement) {
if (registry.has(currentElement)) {
return registry.get(currentElement)
}
currentElement = currentElement.parentNode
}

return null
}
4 changes: 0 additions & 4 deletions src/utils/get-instance-from-vnode.js

This file was deleted.

5 changes: 5 additions & 0 deletions tests/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isVue3 } from '../src/vue'

// --- Utils for testing ---

export const wrapWithMethods = (Component, methods) => ({
Expand All @@ -14,3 +16,6 @@ export const wrapWithMethods = (Component, methods) => ({

export const waitNT = ctx => new Promise(resolve => ctx.$nextTick(resolve))
export const waitRAF = () => new Promise(resolve => requestAnimationFrame(resolve))

export const getInstanceFromVNode = vnode =>
isVue3 ? vnode.__vueParentComponent.ctx : vnode.__vue__

0 comments on commit fe13503

Please sign in to comment.