-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(useMouseLeavePage): Adding useMouseLeavePage function
- Loading branch information
1 parent
eb01041
commit 5e1747c
Showing
12 changed files
with
263 additions
and
4 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
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 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 @@ | ||
export * from './useMouseLeavePage' |
47 changes: 47 additions & 0 deletions
47
src/components/useMouseLeavePage/stories/UseMouseLeavePageDemo.vue
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,47 @@ | ||
<template> | ||
<div class="wrapper"> | ||
<table class="table is-fullwidth"> | ||
<thead> | ||
<tr> | ||
<th>Prop</th> | ||
<th>Value</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>hasLeftPage</td> | ||
<td>{{ hasLeftPage }}</td> | ||
</tr> | ||
<tr> | ||
<td colspan="2"> | ||
<button class="button is-primary" @click="start" v-if="!isTracking"> | ||
Start tracking mouse leave event | ||
</button> | ||
<button class="button is-danger" @click="stop" v-else> | ||
Stop tracking mouse leave event | ||
</button> | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import Vue from 'vue' | ||
import { useMouseLeavePage } from '@src/vue-use-kit' | ||
export default Vue.extend({ | ||
name: 'UseMouseLeavePageDemo', | ||
setup() { | ||
const { hasLeftPage, isTracking, start, stop } = useMouseLeavePage() | ||
return { hasLeftPage, isTracking, start, stop } | ||
} | ||
}) | ||
</script> | ||
|
||
<style scoped> | ||
.wrapper { | ||
min-height: 100vh; | ||
} | ||
</style> |
59 changes: 59 additions & 0 deletions
59
src/components/useMouseLeavePage/stories/useMouseLeavePage.md
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,59 @@ | ||
# useMouseLeavePage | ||
|
||
Vue function that tracks when mouse leaves page boundaries. | ||
|
||
## Reference | ||
|
||
```typescript | ||
function useMouseLeavePage( | ||
runOnMount?: boolean | ||
): { | ||
hasLeftPage: Ref<boolean> | ||
isTracking: Ref<boolean> | ||
start: () => void | ||
stop: () => void | ||
} | ||
``` | ||
|
||
### Parameters | ||
|
||
- `runOnMount: boolean` whether to check mouse leaves page boundaries tracking on mount, `true` by default | ||
|
||
### Returns | ||
|
||
- `hasLeftPage: Ref<boolean>` whether the mouse has left the page or not | ||
- `isTracking: Ref<boolean>` whether this function events are running or not | ||
- `start: Function` the function used to start tracking when the mouse leaves the page boundaries | ||
- `stop: Function` the function used to stop tracking when the mouse leaves the page boundaries | ||
|
||
## Usage | ||
|
||
```html | ||
<template> | ||
<div> | ||
<div> | ||
hasLeftPage: | ||
<pre>{{ hasLeftPage }}</pre> | ||
</div> | ||
<div> | ||
<button @click="start" v-if="!isTracking"> | ||
Start tracking mouse leave event | ||
</button> | ||
<button @click="stop" v-else>Stop tracking mouse leave event</button> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import Vue from 'vue' | ||
import { useMouseLeavePage } from 'vue-use-kit' | ||
export default Vue.extend({ | ||
name: 'UseMouseLeavePageDemo', | ||
setup() { | ||
const { hasLeftPage, isTracking, start, stop } = useMouseLeavePage() | ||
return { hasLeftPage, isTracking, start, stop } | ||
} | ||
}) | ||
</script> | ||
``` |
39 changes: 39 additions & 0 deletions
39
src/components/useMouseLeavePage/stories/useMouseLeavePage.story.ts
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,39 @@ | ||
import { storiesOf } from '@storybook/vue' | ||
import path from 'path' | ||
import StoryTitle from '@src/helpers/StoryTitle.vue' | ||
import UseMouseLeavePageDemo from './UseMouseLeavePageDemo.vue' | ||
|
||
const functionName = 'useMouseLeavePage' | ||
const functionPath = path.resolve(__dirname, '..') | ||
const notes = require(`./${functionName}.md`).default | ||
|
||
const basicDemo = () => ({ | ||
components: { StoryTitle, demo: UseMouseLeavePageDemo }, | ||
template: ` | ||
<div class="container"> | ||
<story-title | ||
function-path="${functionPath}" | ||
source-name="${functionName}" | ||
demo-name="UseMouseLeavePageDemo.vue" | ||
> | ||
<template v-slot:title></template> | ||
<template v-slot:intro> | ||
<p> | ||
<strong>Try moving the mouse outside the page boundaries</strong> to see the | ||
hasLeftPage variable change on the fly. | ||
</p> | ||
<p> | ||
Please note that because this demo is within an iframe | ||
<strong>it will seem that the callback is firing when you are still within the page.</strong> | ||
Click the "Open canvas in new tab" button on the | ||
top right hand corner to see the demo without iframe. | ||
</p> | ||
</template> | ||
</story-title> | ||
<demo /> | ||
</div>` | ||
}) | ||
|
||
storiesOf('sensors|useMouseLeavePage', module) | ||
.addParameters({ notes }) | ||
.add('Demo', basicDemo) |
81 changes: 81 additions & 0 deletions
81
src/components/useMouseLeavePage/useMouseLeavePage.spec.ts
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,81 @@ | ||
import { mount } from '@src/helpers/test' | ||
import { useMouseLeavePage } from '@src/vue-use-kit' | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks() | ||
}) | ||
|
||
const testComponent = (onMount = true) => ({ | ||
template: ` | ||
<div> | ||
<div id="isTracking" v-if="isTracking"></div> | ||
<div id="hasLeftPage" v-if="hasLeftPage"></div> | ||
<button id="start" @click="start"></button> | ||
<button id="stop" @click="stop"></button> | ||
</div> | ||
`, | ||
setup() { | ||
const { hasLeftPage, isTracking, start, stop } = useMouseLeavePage(onMount) | ||
return { hasLeftPage, isTracking, start, stop } | ||
} | ||
}) | ||
|
||
describe('useMouseLeavePage', () => { | ||
const eventName = 'mouseout' | ||
it('should call mouseout onMounted', async () => { | ||
const addEventListenerSpy = jest.spyOn(document, 'addEventListener') | ||
const removeEventListenerSpy = jest.spyOn(document, 'removeEventListener') | ||
const wrapper = mount(testComponent()) | ||
await wrapper.vm.$nextTick() | ||
expect(addEventListenerSpy).toHaveBeenCalledTimes(1) | ||
expect(addEventListenerSpy).toBeCalledWith(eventName, expect.any(Function)) | ||
|
||
// Destroy instance to check if the remove event listener is being called | ||
wrapper.destroy() | ||
expect(removeEventListenerSpy).toHaveBeenCalledTimes(1) | ||
expect(removeEventListenerSpy).toBeCalledWith( | ||
eventName, | ||
expect.any(Function) | ||
) | ||
}) | ||
|
||
it('should call document.addEventListener again when start is called', async () => { | ||
const addEventListenerSpy = jest.spyOn(document, 'addEventListener') | ||
const wrapper = mount(testComponent()) | ||
expect(addEventListenerSpy).toHaveBeenCalledTimes(1) | ||
wrapper.find('#stop').trigger('click') | ||
|
||
// Wait for Vue to append #start in the DOM | ||
await wrapper.vm.$nextTick() | ||
wrapper.find('#start').trigger('click') | ||
expect(addEventListenerSpy).toHaveBeenCalledTimes(1 * 2) | ||
}) | ||
|
||
it('should call document.removeEventListener when stop is called', async () => { | ||
const removeEventListenerSpy = jest.spyOn(document, 'removeEventListener') | ||
const wrapper = mount(testComponent()) | ||
wrapper.find('#stop').trigger('click') | ||
|
||
// Wait for Vue to append #start in the DOM | ||
await wrapper.vm.$nextTick() | ||
expect(removeEventListenerSpy).toHaveBeenCalledTimes(1) | ||
}) | ||
|
||
it('should show #isTracking when onMount is true', async () => { | ||
const wrapper = mount(testComponent(true)) | ||
await wrapper.vm.$nextTick() | ||
expect(wrapper.find('#isTracking').exists()).toBe(true) | ||
}) | ||
|
||
it('should not show #isTracking when onMount is false', async () => { | ||
const wrapper = mount(testComponent(false)) | ||
await wrapper.vm.$nextTick() | ||
expect(wrapper.find('#isTracking').exists()).toBe(false) | ||
}) | ||
|
||
it('should not show #hasLeftPage when onMount is false', async () => { | ||
const wrapper = mount(testComponent(false)) | ||
await wrapper.vm.$nextTick() | ||
expect(wrapper.find('#hasLeftPage').exists()).toBe(false) | ||
}) | ||
}) |
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,29 @@ | ||
import { ref, onMounted, onUnmounted, Ref } from '@vue/composition-api' | ||
|
||
export function useMouseLeavePage(runOnMount = true) { | ||
const isTracking = ref(false) | ||
const hasLeftPage = ref(false) | ||
|
||
const handleMouseOut = (e: any) => { | ||
const from = e.relatedTarget || e.toElement | ||
const mouseHasLeftPage = !from || from.nodeName === 'HTML' | ||
hasLeftPage.value = mouseHasLeftPage | ||
} | ||
|
||
const start = () => { | ||
if (isTracking.value) return | ||
document.addEventListener('mouseout', handleMouseOut) | ||
isTracking.value = true | ||
} | ||
|
||
const stop = () => { | ||
if (!isTracking.value) return | ||
document.removeEventListener('mouseout', handleMouseOut) | ||
isTracking.value = false | ||
} | ||
|
||
onMounted(() => runOnMount && start()) | ||
onUnmounted(stop) | ||
|
||
return { hasLeftPage, isTracking, start, stop } | ||
} |
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