Skip to content

Commit

Permalink
feat(useLocation): Adding useLocation function
Browse files Browse the repository at this point in the history
  • Loading branch information
microcipcip committed Feb 18, 2020
1 parent 4a21698 commit 3361352
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Vue.use(VueCompositionAPI);
- [`useIntersection`](./src/components/useIntersection/stories/useIntersection.md) — tracks intersection of target element with an ancestor element.
[![Demo](https://img.shields.io/badge/demo-馃殌-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-useintersection--demo)
[![Demo](https://img.shields.io/badge/advanced_demo-馃殌-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-useintersection--advanced-demo)
- [`useLocation`](./src/components/useLocation/stories/useLocation.md) — tracks bar navigation location state.
[![Demo](https://img.shields.io/badge/demo-馃殌-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-uselocation--demo)
- [`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--demo)
[![Demo](https://img.shields.io/badge/advanced_demo-馃殌-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usemedia--advanced-demo)
Expand Down
1 change: 1 addition & 0 deletions src/components/useLocation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useLocation'
62 changes: 62 additions & 0 deletions src/components/useLocation/stories/UseLocationDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<template>
<table class="table is-fullwidth">
<thead>
<tr>
<th>Prop</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>locationState</td>
<td>
<pre>{{ JSON.stringify(locationState, null, 2) }}</pre>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button is-primary" @click="push">
Fire push event
</button>
<button class="button is-danger" @click="replace">
Fire replace event
</button>
</td>
</tr>
<tr>
<td colspan="2">
<button class="button is-primary" @click="start" v-if="!isTracking">
Start tracking location
</button>
<button class="button is-danger" @click="stop" v-else>
Stop tracking location
</button>
</td>
</tr>
</tbody>
</table>
</template>

<script lang="ts">
import Vue from 'vue'
import { useLocation } from '@src/vue-use-kit'
export default Vue.extend({
name: 'UseLocationDemo',
setup() {
let count = 0
const url = location.origin + location.pathname + location.search
const push = () => {
count++
history.pushState({ page: count }, '', `${url}&page=${count}`)
}
const replace = () => {
count--
history.replaceState({ page: count }, '', `${url}&page=${count}`)
}
const { locationState, isTracking, start, stop } = useLocation()
return { locationState, isTracking, start, stop, push, replace }
}
})
</script>
23 changes: 23 additions & 0 deletions src/components/useLocation/stories/useLocation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# useLocation

Vue function that tracks bar navigation location state.

## Reference

```typescript
// function useLocation()
```

### Parameters

- `value: string` lorem ipsa

### Returns

- `value: Ref<string>` lorem ipsa

## Usage

```html
<template></template>
```
28 changes: 28 additions & 0 deletions src/components/useLocation/stories/useLocation.story.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { storiesOf } from '@storybook/vue'
import path from 'path'
import StoryTitle from '@src/helpers/StoryTitle.vue'
import UseLocationDemo from './UseLocationDemo.vue'

const functionName = 'useLocation'
const functionPath = path.resolve(__dirname, '..')
const notes = require(`./${functionName}.md`).default

const basicDemo = () => ({
components: { StoryTitle, demo: UseLocationDemo },
template: `
<div class="container">
<story-title
function-path="${functionPath}"
source-name="${functionName}"
demo-name="UseLocationDemo.vue"
>
<template v-slot:title></template>
<template v-slot:intro></template>
</story-title>
<demo />
</div>`
})

storiesOf('sensors|useLocation', module)
.addParameters({ notes })
.add('Demo', basicDemo)
12 changes: 12 additions & 0 deletions src/components/useLocation/useLocation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// import { mount } from '@src/helpers/test'
// import { useLocation } from '@src/vue-use-kit'

afterEach(() => {
jest.clearAllMocks()
})

describe('useLocation', () => {
it('should do something', () => {
// Add test here
})
})
85 changes: 85 additions & 0 deletions src/components/useLocation/useLocation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { ref, onMounted, onUnmounted, Ref } from '@src/api'

// The history methods 'pushState' and 'replaceState' by default do not fire an event
// unless it is coming from user interaction with the browser navigation bar,
// so we are adding a patch to make them detectable
let isPatched = false
const patchHistoryMethodsOnce = () => {
if (isPatched) return
const methods = ['pushState', 'replaceState']
methods.forEach(method => {
const original = (history as any)[method]
;(history as any)[method] = function(state: any) {
// eslint-disable-next-line prefer-rest-params
const result = original.apply(this, arguments)
const event = new Event(method.toLowerCase())
;(event as any).state = state
window.dispatchEvent(event)
return result
}
})

isPatched = true
}

export function useLocation(runOnMount = true) {
const buildState = (trigger: string) => {
const { state, length } = history

const {
hash,
host,
hostname,
href,
origin,
pathname,
port,
protocol,
search
} = location

return {
trigger,
state,
length,
hash,
host,
hostname,
href,
origin,
pathname,
port,
protocol,
search
}
}
const isTracking = ref(false)
const locationState = ref(buildState('load'))

const popState = () => (locationState.value = buildState('popstate'))
const pushState = () => (locationState.value = buildState('pushstate'))
const replaceState = () => (locationState.value = buildState('replacestate'))

const start = () => {
patchHistoryMethodsOnce()

if (isTracking.value) return
isTracking.value = true
window.addEventListener('popstate', popState)
window.addEventListener('pushstate', pushState)
window.addEventListener('replacestate', replaceState)
}

const stop = () => {
if (!isTracking.value) return
isTracking.value = false
window.removeEventListener('popstate', popState)
window.removeEventListener('pushstate', pushState)
window.removeEventListener('replacestate', replaceState)
}

onMounted(() => runOnMount && start())
onUnmounted(stop)

return { locationState, isTracking, start, stop }
}
1 change: 1 addition & 0 deletions src/vue-use-kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './components/useGeolocation'
export * from './components/useHover'
export * from './components/useIdle'
export * from './components/useIntersection'
export * from './components/useLocation'
export * from './components/useMedia'
export * from './components/useMouse'
export * from './components/useMouseElement'
Expand Down

0 comments on commit 3361352

Please sign in to comment.