Skip to content

Commit 29646ee

Browse files
committed
feat: Added useHover function
1 parent b6e9d40 commit 29646ee

File tree

12 files changed

+205
-46
lines changed

12 files changed

+205
-46
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ Please check the [documentation](https://microcipcip.github.io/vue-use-kit/) to
1919
## APIs
2020

2121
- Sensors
22+
- [`useHover`](./src/components/useHover/stories/useHover.md) — tracks mouse hover state of a given element. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usemedia--basic-demo)
2223
- [`useMedia`](./src/components/useMedia/stories/useMedia.md) — tracks state of a CSS media query. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usemedia--basic-demo)
2324
- [`useMouse`](./src/components/useMouse/stories/useMouse.md) — tracks the mouse's position. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usemouse--demo)
2425
- [`useMouseElement`](./src/components/useMouseElement/stories/useMouseElement.md) — tracks the mouse's position relative to given element. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usemouseelement--demo)
2526
- Animations
26-
- [`useTimeoutFn`](./src/components/useTimeoutFn/stories/useTimeoutFn.md) — calls function after a timeout. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/animations-usetimeoutfn--demo)
27+
- [`useTimeout`](./src/components/useTimeout/stories/useTimeout.md) — returns `isReady` prop as `true` when timer is completed. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/animations-usetimeout--demo)
28+
- [`useTimeoutFn`](./src/components/useTimeoutFn/stories/useTimeoutFn.md) — calls function when timer is completed. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/animations-usetimeoutfn--demo)
2729
- Utils
2830
- [`getQuery`](./src/components/getQuery/stories/getQuery.md) — get a CSS media query string. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/utils-getquery--demo)
2931

src/components/useHover/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './useHover'
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<template>
2+
<div class="use-hover" ref="useHoverRef">
3+
<div>
4+
<div class="use-hover__emoji" v-if="!isHovered">😴</div>
5+
<div class="use-hover__emoji" v-else>😃</div>
6+
</div>
7+
</div>
8+
</template>
9+
10+
<script lang="ts">
11+
import Vue from 'vue'
12+
import { ref } from '../../../api'
13+
import { useHover } from '../../../vue-use-kit'
14+
15+
export default Vue.extend({
16+
name: 'UseHoverDemo',
17+
setup() {
18+
const useHoverRef = ref(null)
19+
const isHovered = useHover(useHoverRef)
20+
return { isHovered, useHoverRef }
21+
}
22+
})
23+
</script>
24+
25+
<style>
26+
.use-hover {
27+
cursor: default;
28+
display: flex;
29+
align-items: center;
30+
justify-content: center;
31+
min-height: 400px;
32+
background: #b2b594;
33+
}
34+
35+
.use-hover__emoji {
36+
font-size: 90px;
37+
}
38+
</style>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# useHover
2+
3+
Vue function that tracks mouse hover state of a given element.
4+
5+
## Reference
6+
7+
```typescript
8+
useHover(element: Ref<null | Element>): Ref<boolean>
9+
```
10+
11+
### Parameters
12+
13+
- `element: Ref<null | Element>` the element used for tracking the mouse hover state
14+
15+
### Returns
16+
17+
- `isHovered: boolean` whether the element is currently hovered or not
18+
19+
## Usage
20+
21+
```html
22+
<template>
23+
<div ref="useHoverRef">
24+
<div v-if="!isHovered">😴</div>
25+
<div v-else>😃</div>
26+
</div>
27+
</template>
28+
29+
<script lang="ts">
30+
import Vue from 'vue'
31+
import { ref } from '../../../api'
32+
import { useHover } from 'vue-use-kit'
33+
34+
export default Vue.extend({
35+
name: 'UseHoverDemo',
36+
setup() {
37+
const useHoverRef = ref(null)
38+
const isHovered = useHover(useHoverRef)
39+
return { isHovered, useHoverRef }
40+
}
41+
})
42+
</script>
43+
```
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { storiesOf } from '@storybook/vue'
2+
import StoryTitle from '../../../helpers/StoryTitle.vue'
3+
import UseHoverDemo from './UseHoverDemo.vue'
4+
5+
const storiesPath = __dirname
6+
const notes = require('./useHover.md').default
7+
8+
const basicDemo = () => ({
9+
components: { StoryTitle, demo: UseHoverDemo },
10+
template: `
11+
<div class="container">
12+
<story-title stories-path="${storiesPath}" file-name="UseHoverDemo.vue">
13+
<template v-slot:title></template>
14+
<template v-slot:intro>
15+
Try to move the mouse hover the box below to see the emoji change of expression.
16+
</template>
17+
</story-title>
18+
<demo />
19+
</div>`
20+
})
21+
22+
storiesOf('sensors|useHover', module)
23+
.addParameters({ notes })
24+
.add('Demo', basicDemo)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
describe('useHover', () => {
2+
it('should do something', () => {
3+
// Add test here
4+
})
5+
})
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ref, onMounted, onUnmounted, Ref } from '../../api'
2+
3+
export function useHover(element: Ref<null | Element>) {
4+
const isHovered = ref(false)
5+
6+
const mouseEnterHandler = (e: Event) => {
7+
isHovered.value = true
8+
}
9+
10+
const mouseLeaveHandler = (e: Event) => {
11+
isHovered.value = false
12+
}
13+
14+
onMounted(() => {
15+
if (!element.value) return
16+
element.value.addEventListener('mouseenter', mouseEnterHandler)
17+
element.value.addEventListener('mouseleave', mouseLeaveHandler)
18+
})
19+
20+
onUnmounted(() => {
21+
if (!element.value) return
22+
element.value.removeEventListener('mouseenter', mouseEnterHandler)
23+
element.value.removeEventListener('mouseleave', mouseLeaveHandler)
24+
})
25+
26+
return isHovered
27+
}

src/components/useMouseElement/stories/UseMouseElementDemo.vue

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,27 @@
3535
</td>
3636
</tr>
3737
<tr>
38-
<td>el.x, el.y</td>
38+
<td>elInfoX, elInfoY</td>
3939
<td>
4040
Emoji element position <strong>relative to the document</strong>
4141
</td>
4242
<td>
43-
<span>{{ toInt(el.x) }}px</span>
43+
<span>{{ toInt(elInfoX) }}px</span>
4444
</td>
4545
<td>
46-
<span>{{ toInt(el.y) }}px</span>
46+
<span>{{ toInt(elInfoY) }}px</span>
4747
</td>
4848
</tr>
4949
<tr>
50-
<td>el.w, el.h</td>
50+
<td>elInfoW, elInfoH</td>
5151
<td>
5252
Emoji element width and height
5353
</td>
5454
<td>
55-
<span>{{ toInt(el.w) }}px</span>
55+
<span>{{ toInt(elInfoW) }}px</span>
5656
</td>
5757
<td>
58-
<span>{{ toInt(el.h) }}px</span>
58+
<span>{{ toInt(elInfoH) }}px</span>
5959
</td>
6060
</tr>
6161
</tbody>
@@ -76,7 +76,16 @@ export default Vue.extend({
7676
const emojiRef = ref(null)
7777
let pauseEmoji = ref(true)
7878
79-
const { docX, docY, elX, elY, el } = useMouseElement(emojiRef)
79+
const {
80+
docX,
81+
docY,
82+
elX,
83+
elY,
84+
elInfoX,
85+
elInfoY,
86+
elInfoW,
87+
elInfoH
88+
} = useMouseElement(emojiRef)
8089
8190
const emojiStyle = computed(() => {
8291
if (pauseEmoji.value) return
@@ -114,7 +123,10 @@ export default Vue.extend({
114123
docY,
115124
elX,
116125
elY,
117-
el
126+
elInfoX,
127+
elInfoY,
128+
elInfoW,
129+
elInfoH
118130
}
119131
}
120132
})

src/components/useMouseElement/stories/useMouseElement.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@ useMouseElement(element: Ref<null | Element>): {
1111
docY: Ref<number>;
1212
elX: Ref<number>;
1313
elY: Ref<number>;
14-
el: Ref<{
15-
x: number;
16-
y: number;
17-
w: number;
18-
h: number;
19-
}>;
14+
elInfoX: Ref<number>;
15+
elInfoY: Ref<number>;
16+
elInfoW: Ref<number>;
17+
elInfoH: Ref<number>;
2018
}
2119
```
2220

@@ -30,10 +28,10 @@ useMouseElement(element: Ref<null | Element>): {
3028
- `docY: number` the mouse `y` position relative to the document
3129
- `elX: number` the mouse `x` position relative to the given element
3230
- `elY: number` the mouse `y` position relative to the given element
33-
- `el.x: number` the element `x` position
34-
- `el.y: number` the element `y` position
35-
- `el.w: number` the element `width` value
36-
- `el.h: number` the element `height` value
31+
- `elInfoX: number` the element `x` position
32+
- `elInfoY: number` the element `y` position
33+
- `elInfoW: number` the element `width` value
34+
- `elInfoH: number` the element `height` value
3735

3836
## Usage
3937

src/components/useMouseElement/useMouseElement.spec.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,30 @@ import { useMouseElement } from '../../vue-use-kit'
44

55
const testComponent = () => ({
66
template: `
7-
<div ref="div">
7+
<div ref="divRef">
88
<div id="docX" v-if="docX" />
99
<div id="docY" v-if="docY" />
1010
<div id="elX" v-if="elX" />
1111
<div id="elY" v-if="elY" />
12-
<div id="el.x" v-if="el.x" />
13-
<div id="el.y" v-if="el.y" />
14-
<div id="el.w" v-if="el.w" />
15-
<div id="el.h" v-if="el.h" />
12+
<div id="elInfoX" v-if="elInfoX" />
13+
<div id="elInfoY" v-if="elInfoY" />
14+
<div id="elInfoW" v-if="elInfoW" />
15+
<div id="elInfoH" v-if="elInfoH" />
1616
</div>
1717
`,
1818
setup() {
1919
const divRef = ref(null)
20-
const { docX, docY, elX, elY, el } = useMouseElement(divRef)
21-
return { docX, docY, elX, elY, el }
20+
const {
21+
docX,
22+
docY,
23+
elX,
24+
elY,
25+
elInfoX,
26+
elInfoY,
27+
elInfoW,
28+
elInfoH
29+
} = useMouseElement(divRef)
30+
return { docX, docY, elX, elY, elInfoX, elInfoY, elInfoW, elInfoH, divRef }
2231
}
2332
})
2433

@@ -44,9 +53,9 @@ describe('useMouseElement', () => {
4453
expect(wrapper.find('#docY').exists()).toBe(false)
4554
expect(wrapper.find('#elX').exists()).toBe(false)
4655
expect(wrapper.find('#elY').exists()).toBe(false)
47-
expect(wrapper.find('#el.x').exists()).toBe(false)
48-
expect(wrapper.find('#el.y').exists()).toBe(false)
49-
expect(wrapper.find('#el.w').exists()).toBe(false)
50-
expect(wrapper.find('#el.h').exists()).toBe(false)
56+
expect(wrapper.find('#elInfoX').exists()).toBe(false)
57+
expect(wrapper.find('#elInfoY').exists()).toBe(false)
58+
expect(wrapper.find('#elInfoW').exists()).toBe(false)
59+
expect(wrapper.find('#elInfoH').exists()).toBe(false)
5160
})
5261
})

0 commit comments

Comments
 (0)