Skip to content

Commit

Permalink
fix(activatable): get activator element from event or nested component (
Browse files Browse the repository at this point in the history
#9294)

* fix(activatable): get activator element from event or nested component

fixes #8846

* fix: un-break activator prop

* chore: comments
  • Loading branch information
KaelWD authored and johnleider committed Oct 10, 2019
1 parent 4fe4d3a commit 4b73dd2
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,27 +127,24 @@ describe('activatable.ts', () => {
},
})

const activatorElement = wrapper.vm.activatorElement as any

await wrapper.vm.$nextTick()

expect(wrapper.vm.isActive).toBe(false)
expect(el).toEqual(activatorElement)
activatorElement.dispatchEvent(new Event('click'))
el.dispatchEvent(new Event('click'))
expect(wrapper.vm.isActive).toBe(true)

wrapper.setProps({ openOnHover: true, value: false })

await wrapper.vm.$nextTick()

expect(wrapper.vm.isActive).toBe(false)
activatorElement.dispatchEvent(new Event('mouseenter'))
el.dispatchEvent(new Event('mouseenter'))

await new Promise(resolve => setTimeout(resolve, wrapper.vm.openDelay))

expect(wrapper.vm.isActive).toBe(true)

activatorElement.dispatchEvent(new Event('mouseleave'))
el.dispatchEvent(new Event('mouseleave'))
await new Promise(resolve => setTimeout(resolve, wrapper.vm.leaveDelay))

expect(wrapper.vm.isActive).toBe(false)
Expand Down
36 changes: 23 additions & 13 deletions packages/vuetify/src/mixins/activatable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default baseMixins.extend({
},

data: () => ({
// Do not use this directly, call getActivator() instead
activatorElement: null as HTMLElement | null,
activatorNode: [] as VNode[],
events: ['click', 'mouseenter', 'mouseleave'],
Expand All @@ -41,11 +42,6 @@ export default baseMixins.extend({

watch: {
activator: 'resetActivator',
activatorElement (val) {
if (!val) return

this.addActivatorEvents()
},
openOnHover: 'resetActivator',
},

Expand All @@ -56,7 +52,7 @@ export default baseMixins.extend({
consoleError(`The activator slot must be bound, try '<template v-slot:activator="{ on }"><v-btn v-on="on">'`, this)
}

this.getActivator()
this.addActivatorEvents()
},

beforeDestroy () {
Expand All @@ -68,14 +64,14 @@ export default baseMixins.extend({
if (
!this.activator ||
this.disabled ||
!this.activatorElement
!this.getActivator()
) return

this.listeners = this.genActivatorListeners()
const keys = Object.keys(this.listeners)

for (const key of keys) {
(this.activatorElement as any).addEventListener(key, this.listeners[key])
this.getActivator()!.addEventListener(key, this.listeners[key] as any)
}
},
genActivator () {
Expand Down Expand Up @@ -111,7 +107,8 @@ export default baseMixins.extend({
}
} else {
listeners.click = (e: MouseEvent) => {
if (this.activatorElement) this.activatorElement.focus()
const activator = this.getActivator(e)
if (activator) activator.focus()

this.isActive = !this.isActive
}
Expand All @@ -128,20 +125,32 @@ export default baseMixins.extend({
if (this.activator) {
const target = this.internalActivator ? this.$el : document

// Selector
if (typeof this.activator === 'string') {
// Selector
activator = target.querySelector(this.activator)
// VNode
} else if ((this.activator as any).$el) {
// Component (ref)
activator = (this.activator as any).$el
// HTMLElement | Element
} else {
// HTMLElement | Element
activator = this.activator
}
} else if (e) {
// Activated by a click event
activator = (e.currentTarget || e.target) as HTMLElement
} else if (this.activatorNode.length) {
activator = this.activatorNode[0].elm as HTMLElement
// Last resort, use the contents of the activator slot
const vm = this.activatorNode[0].componentInstance
if (
vm &&
vm.$options.mixins && // Activatable is indirectly used via Menuable
vm.$options.mixins.some((m: any) => m.options && ['activatable', 'menuable'].includes(m.options.name))
) {
// Activator is actually another activatible component, use its activator (#8846)
activator = (vm as any).getActivator()
} else {
activator = this.activatorNode[0].elm as HTMLElement
}
}

this.activatorElement = activator
Expand Down Expand Up @@ -179,6 +188,7 @@ export default baseMixins.extend({
resetActivator () {
this.activatorElement = null
this.getActivator()
this.addActivatorEvents()
},
},
})

0 comments on commit 4b73dd2

Please sign in to comment.