Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ Vue.use(VueCompositionAPI);
- Sensors
- [`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-usehover--demo)
- [`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)
- [`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 All @@ -70,7 +72,7 @@ Vue.use(VueCompositionAPI);
- [`useMouseElement`](./src/components/useMouseElement/stories/useMouseElement.md) — tracks the mouse 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)
- Animations
- [`useInterval`](./src/components/useInterval/stories/useInterval.md) — updates the `counter` value repeatedly on a fixed time delay.
- [`useInterval`](./src/components/useInterval/stories/useInterval.md) — updates `counter` value repeatedly on a fixed time delay.
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/animations-useinterval--demo)
- [`useIntervalFn`](./src/components/useIntervalFn/stories/useIntervalFn.md) — calls function repeatedly on a fixed time delay.
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/animations-useintervalfn--demo)
Expand Down
4 changes: 2 additions & 2 deletions src/components/useClickAway/stories/useClickAway.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ Vue function that triggers a callback when the user clicks outside of the target
```typescript
useClickAway(
elRef: Ref<null | Element>,
onClickAway: (e: Event) => void,
callback: (e: Event) => void,
events?: string[]
): void;
```

### Parameters

- `elRef: Ref<null | Element>` the element to check for click away events
- `onClickAway: Function` the callback to run when triggering a click away
- `callback: Function` the callback to run when triggering a click away
- `events: string[]` list of events to listen to, defaults to `['mousedown', 'touchstart']`

## Usage
Expand Down
4 changes: 2 additions & 2 deletions src/components/useClickAway/useClickAway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ const defaultEvents = ['mousedown', 'touchstart']

export function useClickAway(
elRef: Ref<null | Element>,
onClickAway: (e: Event) => void,
callback: (e: Event) => void,
events = defaultEvents
) {
const handler = (e: Event) => {
if (elRef.value && !elRef.value.contains(e.target as Node)) {
onClickAway(e)
callback(e)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/useHover/stories/UseHoverDemo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default Vue.extend({
})
</script>

<style>
<style scoped>
.use-hover {
cursor: default;
display: flex;
Expand Down
1 change: 1 addition & 0 deletions src/components/useIntersection/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useIntersection'
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<template>
<div class="section">
<div class="intersection" v-for="(item, index) in divElements">
<use-intersection-element-demo
class="intersection__el"
:options="intersectionOpts"
@changed="handleIntersectionChange"
>
<video controls loop>
<source :src="getAlternateVideoUrl(index)" type="video/mp4" />
</video>
</use-intersection-element-demo>
</div>
</div>
</template>

<script lang="ts">
import Vue from 'vue'
import UseIntersectionElementDemo from './UseIntersectionElementDemo.vue'

const getAlternateVideoUrl = (n: number) => {
const videoNumber = n % 2 === 0 ? 1 : 2
return `/demo/video${videoNumber}.mp4`
}

const setVideoPausedValue = ($el: Element, val: string) =>
$el.setAttribute('data-is-paused', val)

const divElements = new Array(10)

export default Vue.extend({
name: 'UseIntersectionDemo',
components: { UseIntersectionElementDemo },
setup() {
const intersectionOpts = {
root: null,
threshold: 1
}

const handleIntersectionChange = ({
target,
intersectionRatio
}: IntersectionObserverEntry) => {
const isVisible = intersectionRatio === 1
const $video = target.querySelector('video')
if (!$video) return

// Video pause logic
if (!isVisible) {
if ($video.paused) return
$video.pause()
setVideoPausedValue($video, '1')
}

// Video play logic
if (isVisible && $video.dataset.isPaused === '1'){
$video.play()
setVideoPausedValue($video, '0')
}
}

return {
divElements,
intersectionOpts,
getAlternateVideoUrl,
handleIntersectionChange
}
}
})
</script>

<style scoped>
.section {
padding: 20px 0;
}

.intersection {
display: flex;
align-items: flex-start;
justify-content: center;
height: 920px;
}

.intersection__el {
position: relative;
}
</style>
108 changes: 108 additions & 0 deletions src/components/useIntersection/stories/UseIntersectionDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<template>
<div class="section">
<div class="intersection" v-for="el in divElements">
<use-intersection-element-demo
class="intersection__el"
:options="intersectionOpts"
@changed="handleIntersectionChange"
@paused="handleIntersectionPaused"
/>
</div>
</div>
</template>

<script lang="ts">
import Vue from 'vue'
import UseIntersectionElementDemo from './UseIntersectionElementDemo.vue'

export default Vue.extend({
name: 'UseIntersectionDemo',
components: { UseIntersectionElementDemo },
setup() {
const intersectionOpts = {
root: null,
rootMargin: '-40px 0px -40px',
threshold: 1
}

const divElements = new Array(100)

const handleIntersectionChange = ({
target,
intersectionRatio
}: IntersectionObserverEntry) => {
const isVisible = intersectionRatio === 1
target.classList.toggle('-is-active', isVisible)
}

const handleIntersectionPaused = (target: Element, isPaused: boolean) => {
target.classList.toggle('-is-paused', isPaused)
}

return {
divElements,
intersectionOpts,
handleIntersectionChange,
handleIntersectionPaused
}
}
})
</script>

<style scoped>
.section {
padding: 20px 0;
}

.intersection {
display: flex;
align-items: center;
justify-content: center;
height: 120px;
}

/* El */
.intersection__el {
position: relative;
width: 80px;
height: 80px;
}

/* Action buttons */
/deep/ .intersection__el .button {
position: absolute;
top: 50%;
left: 130px;
transform: translateY(-50%);
}

/* Circle */
.intersection__el:after {
content: 'Not intersecting';
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 50%;
left: 50%;
width: 100px;
height: 40px;
border-radius: 8px;
background: red;
color: white;
font-size: 12px;
transition: all 0.7s ease-in-out;
transform: translate(-50%, -50%) scale(1);
}

.intersection__el.-is-active:after {
content: 'Intersecting';
background: green;
transform: translate(-50%, -50%) scale(1.4);
}

.intersection__el.-is-paused:after {
content: 'Disabled';
background: orange;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<template>
<div ref="elRef">
<slot></slot>
<button
class="button is-primary"
@click="handleStart"
v-if="!isObserving"
title="Start observing"
>
<span class="icon"><i class="fas fa-play"></i></span>
</button>
<button
class="button is-warning"
@click="handleStop"
v-else
title="Stop observing"
>
<span class="icon"><i class="fas fa-pause"></i></span>
</button>
</div>
</template>

<script lang="ts">
import Vue from 'vue'
import { ref, watch } from '@src/api'
import { useIntersection } from '@src/vue-use-kit'
export default Vue.extend({
name: 'UseIntersectionElementDemo',
props: {
options: {
default: {
root: null,
rootMargin: '0px',
threshold: 0
}
}
},
setup({ options }, { emit }) {
const elRef = ref(null)

const { observedEntry, start, stop } = useIntersection(
elRef,
options as IntersectionObserverInit
)

watch(() => {
if (!observedEntry.value) return
emit('changed', observedEntry.value)
})

let isObserving = ref(true)
const handleStart = () => {
if (!observedEntry.value) return
start()
emit('paused', observedEntry.value.target, false)
isObserving.value = true
}

const handleStop = () => {
if (!observedEntry.value) return
stop()
emit('paused', observedEntry.value.target, true)
isObserving.value = false
}

return { handleStart, handleStop, isObserving, elRef }
}
})
</script>
Loading