Skip to content

Commit

Permalink
feat: add sensor/useIntersection hook
Browse files Browse the repository at this point in the history
  • Loading branch information
jo0ger committed Oct 30, 2019
1 parent 2be6086 commit 207a92a
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ and then:
* [ ] `useBattery`: tracks device battery state
* [x] [`useGeolocation`](./src/hooks/sensor/useGeolocation/doc.md): tracks geo location state of user's device
* [ ] `useIdle`: tracks whether user is being inactive
* [ ] `useIntersection`: tracks an HTML element's intersection
* [x] [`useIntersection`](./src/hooks/sensor/useIntersection/doc.md): tracks an HTML element's intersection
* [ ] `useEvent`: subscribe to events
* [x] [`useMedia`](./src/hooks/sensor/useMedia/doc.md): tracks state of a CSS media query
* [x] [`useMediaDevices`](./src/hooks/sensor/useMediaDevices/doc.md): tracks connected hardware devices
Expand Down
64 changes: 64 additions & 0 deletions src/hooks/sensor/useIntersection/demo.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { storiesOf } from '@storybook/vue'
import { createComponent } from '@vue/composition-api'
import Doc from '../../../__stories__/components/Doc'
import { useIntersection } from '../../..'

const Spacer = () => (
<div
style={{
width: '200px',
height: '300px',
backgroundColor: 'whitesmoke'
}}
/>
)

const Demo = createComponent({
setup(_, ctx) {
const intersection = useIntersection(
() => (ctx as any).refs.tracker as HTMLElement,
{
root: null,
rootMargin: '0px',
threshold: 1
}
)
return { intersection }
},
render() {
const { intersection } = this
return (
<div
style={{
width: '400px',
height: '400px',
backgroundColor: 'whitesmoke',
overflow: 'scroll'
}}
>
Scroll me
<Spacer />
<div
ref="tracker"
style={{
width: '100px',
height: '100px',
padding: '20px',
backgroundColor: 'palegreen'
}}
>
{intersection && intersection.intersectionRatio < 1
? 'Obscured'
: 'Fully in view'}
</div>
<Spacer />
</div>
)
}
})

const Docs = () => <Doc md={require('./doc.md')}></Doc>

storiesOf('Sensor|useIntersection', module)
.add('Docs', () => Docs as any)
.add('Demo', () => Demo)
72 changes: 72 additions & 0 deletions src/hooks/sensor/useIntersection/doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# useIntersection

Vue hook that tracks the changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. Uses the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) and returns a [IntersectionObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry).

> Browser environment is required
## Usage

```jsx
import { createComponent } from '@vue/composition-api'
import { useIntersection } from 'vuses'

const Spacer = () => (
<div
style={{
width: '200px',
height: '300px',
backgroundColor: 'whitesmoke',
}}
/>
)

const Demo = createComponent({
setup(_, ctx) {
const intersection = useIntersection(() => (ctx as any).refs.tracker as HTMLElement, {
root: null,
rootMargin: '0px',
threshold: 1
})
return { intersection }
},
render() {
const { intersection } = this
return (
<div
style={{
width: '400px',
height: '400px',
backgroundColor: 'whitesmoke',
overflow: 'scroll',
}}
>
Scroll me
<Spacer />
<div
ref="tracker"
style={{
width: '100px',
height: '100px',
padding: '20px',
backgroundColor: 'palegreen',
}}
>
{intersection && intersection.intersectionRatio < 1 ? 'Obscured' : 'Fully in view'}
</div>
<Spacer />
</div>
)
}
})
```

## Reference

```typescript {4-6}
type IntersectionState = IntersectionObserverEntry | null

function useIntersection(
elem: HTMLElement | (() => HTMLElement),
options: IntersectionObserverInit
): Ref<IntersectionState>
```
33 changes: 33 additions & 0 deletions src/hooks/sensor/useIntersection/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Ref, ref, onMounted, onUnmounted } from '@vue/composition-api'
import { isFunction } from '../../../utils'

export type IntersectionState = IntersectionObserverEntry | null

export default function useIntersection(
elem: HTMLElement | (() => HTMLElement),
options: IntersectionObserverInit
): Ref<IntersectionState> {
const getElem = isFunction(elem) ? elem : () => elem
const state = ref<IntersectionState>(null)
let observer: IntersectionObserver | null = null

const handler = (entries: IntersectionObserverEntry[]) => {
state.value = entries[0]
}

onMounted(() => {
const el = getElem()
if (!el) return

observer = new IntersectionObserver(handler, options)
observer.observe(el)
})

onUnmounted(() => {
if (observer) {
observer.disconnect()
}
})

return state
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export { default as useBattery } from './hooks/sensor/useBattery'
export { default as useMedia } from './hooks/sensor/useMedia'
export { default as useMediaDevices } from './hooks/sensor/useMediaDevices'
export { default as useDeviceMotion } from './hooks/sensor/useDeviceMotion'
export { default as useIntersection } from './hooks/sensor/useIntersection'

// Side Effect Hooks
export { default as useTitle } from './hooks/sideEffect/useTitle'
Expand Down

0 comments on commit 207a92a

Please sign in to comment.