-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(v-b-hover): new directive for reacting to hover changes (#4771)
- Loading branch information
1 parent
1e02769
commit b7adc6d
Showing
11 changed files
with
243 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# Hover | ||
|
||
> `v-b-hover` is a lightweight directive that allows you to react when an element either becomes | ||
> hovered or unhovered. | ||
The `v-b-hover` directive can be used as an alternative to using custom CSS to handle hover states. | ||
|
||
The `v-b-hover` directive was added in version `2.5.0`. | ||
|
||
## Overview | ||
|
||
- `v-b-hover` will call your callback method with a boolean value indicating if the element is | ||
hovered or not. | ||
- The directive can be placed on almost any element or component. | ||
- Internally, BootstrapVue uses this directive in several components. | ||
|
||
## Directive syntax and usage | ||
|
||
```html | ||
<div v-b-hover="callback">content</div> | ||
``` | ||
|
||
Where callback is required: | ||
|
||
- A function reference that will be called whenever hover state changes. The callback is passed a | ||
single boolean argument. `true` indicates that the element (or component) is hovered by the users | ||
pointing device, or `false` if the element is not hovered. | ||
|
||
The directive has no modifiers. | ||
|
||
### Usage example | ||
|
||
```html | ||
<template> | ||
<div v-b-hover="hoverHandler"> ... </div> | ||
</template> | ||
|
||
<script> | ||
export default { | ||
methods: { | ||
hoverHandler(isHovered) { | ||
if (isHovered) { | ||
// Do something | ||
} else { | ||
// Do something else | ||
} | ||
} | ||
} | ||
} | ||
</script> | ||
``` | ||
|
||
## Live example | ||
|
||
In the following, we are swapping icons and tet color depending on the hover state of the element: | ||
|
||
```html | ||
<template> | ||
<div> | ||
<div v-b-hover="handleHover" class="border rounded py-3 px-4"> | ||
<b-icon v-if="isHovered" icon="battery-full" scale="2"></b-icon> | ||
<b-icon v-else icon="battery" scale="2"></b-icon> | ||
<span class="ml-2" :class="isHovered ? 'text-danger' : ''">Hover this area</span> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
export default { | ||
data() { | ||
return { | ||
isHovered: false | ||
} | ||
}, | ||
methods: { | ||
handleHover(hovered) { | ||
this.isHovered = hovered | ||
} | ||
} | ||
} | ||
</script> | ||
|
||
<!-- b-v-hover-example.vue --> | ||
``` | ||
|
||
## Accessibility concerns | ||
|
||
Hover state should not be used to convey special meaning, as screen reader users and keyboard only | ||
users typically ac not typically trigger hover state on elements. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// v-b-hover directive | ||
import { isBrowser } from '../../utils/env' | ||
import { EVENT_OPTIONS_NO_CAPTURE, eventOnOff } from '../../utils/events' | ||
import { isFunction } from '../../utils/inspect' | ||
|
||
// --- Constants --- | ||
|
||
const PROP = '__BV_hover_handler__' | ||
const MOUSEENTER = 'mouseenter' | ||
const MOUSELEAVE = 'mouseleave' | ||
|
||
// --- Utility methods --- | ||
|
||
const createListener = handler => { | ||
const listener = evt => { | ||
handler(evt.type === MOUSEENTER, evt) | ||
} | ||
listener.fn = handler | ||
return listener | ||
} | ||
|
||
const updateListeners = (on, el, listener) => { | ||
eventOnOff(on, el, MOUSEENTER, listener, EVENT_OPTIONS_NO_CAPTURE) | ||
eventOnOff(on, el, MOUSELEAVE, listener, EVENT_OPTIONS_NO_CAPTURE) | ||
} | ||
|
||
// --- Directive bind/unbind/update handler --- | ||
|
||
const directive = (el, { value: handler = null }) => { | ||
if (isBrowser) { | ||
const listener = el[PROP] | ||
const hasListener = isFunction(listener) | ||
const handlerChanged = !(hasListener && listener.fn === handler) | ||
if (hasListener && handlerChanged) { | ||
updateListeners(false, el, listener) | ||
delete el[PROP] | ||
} | ||
if (isFunction(handler) && handlerChanged) { | ||
el[PROP] = createListener(handler) | ||
updateListeners(true, el, el[PROP]) | ||
} | ||
} | ||
} | ||
|
||
// VBHover directive | ||
|
||
export const VBHover = { | ||
bind: directive, | ||
componentUpdated: directive, | ||
unbind(el) { | ||
directive(el, { value: null }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { mount, createLocalVue as CreateLocalVue } from '@vue/test-utils' | ||
import { waitNT } from '../../../tests/utils' | ||
import { VBHover } from './hover' | ||
|
||
describe('v-b-hover directive', () => { | ||
it('works', async () => { | ||
const localVue = new CreateLocalVue() | ||
let hovered1 = false | ||
let hovered2 = false | ||
const App = localVue.extend({ | ||
data() { | ||
return { | ||
text: 'FOO', | ||
changeHandler: false | ||
} | ||
}, | ||
directives: { | ||
BHover: VBHover | ||
}, | ||
methods: { | ||
handleHover1(isHovered) { | ||
hovered1 = isHovered | ||
}, | ||
handleHover2(isHovered) { | ||
hovered2 = isHovered | ||
} | ||
}, | ||
template: `<div v-b-hover="changeHandler ? handleHover2 : handleHover1"><span>{{ text }}</span></div>` | ||
}) | ||
const wrapper = mount(App) | ||
|
||
expect(wrapper.isVueInstance()).toBe(true) | ||
expect(hovered1).toBe(false) | ||
|
||
wrapper.trigger('mouseenter') | ||
await waitNT(wrapper.vm) | ||
|
||
expect(hovered1).toBe(true) | ||
|
||
wrapper.trigger('mouseleave') | ||
await waitNT(wrapper.vm) | ||
|
||
expect(hovered1).toBe(false) | ||
|
||
wrapper.setData({ text: 'BAR' }) | ||
|
||
wrapper.trigger('mouseenter') | ||
await waitNT(wrapper.vm) | ||
|
||
expect(hovered1).toBe(true) | ||
|
||
wrapper.setData({ changeHandler: true }) | ||
|
||
wrapper.trigger('mouseenter') | ||
await waitNT(wrapper.vm) | ||
|
||
expect(hovered2).toBe(true) | ||
|
||
wrapper.destroy() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// | ||
// VBHover | ||
// | ||
import Vue, { DirectiveOptions } from 'vue' | ||
import { BvPlugin } from '../../' | ||
|
||
// Plugin | ||
export declare const VBHoverPlugin: BvPlugin | ||
|
||
// directive: v-b-hover | ||
export declare const VBHover: DirectiveOptions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { VBHover } from './hover' | ||
import { pluginFactory } from '../../utils/plugins' | ||
|
||
const VBHoverPlugin = /*#__PURE__*/ pluginFactory({ | ||
directives: { VBHover } | ||
}) | ||
|
||
export { VBHoverPlugin, VBHover } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"name": "@bootstrap-vue/v-b-hover", | ||
"version": "1.0.0", | ||
"meta": { | ||
"title": "Hover", | ||
"description": "A lightweight directive that allows you to react when an element either becomes hovered or unhovered", | ||
"directive": "VBHover", | ||
"new": true, | ||
"version": "2.5.0", | ||
"expression": [ | ||
"Function" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.