From cad94440a9db26d8fcce563752795b5894ada47f Mon Sep 17 00:00:00 2001 From: Salvatore Tedde Date: Sat, 15 Feb 2020 00:37:19 +0000 Subject: [PATCH 1/2] fix: Simplify useTimeout logic --- README.md | 2 + src/components/useIntervalFn/index.ts | 1 + .../stories/UseIntervalFnDemo.vue | 49 +++++++++++++++ .../useIntervalFn/stories/useIntervalFn.md | 63 +++++++++++++++++++ .../stories/useIntervalFn.story.ts | 28 +++++++++ .../useIntervalFn/useIntervalFn.spec.ts | 8 +++ src/components/useIntervalFn/useIntervalFn.ts | 23 +++++++ src/components/useRaf/stories/UseRafDemo.vue | 15 ++--- .../useTimeout/stories/UseTimeoutDemo.vue | 13 ++-- .../useTimeout/stories/useTimeout.md | 14 ++--- src/components/useTimeout/useTimeout.spec.ts | 4 +- src/components/useTimeout/useTimeout.ts | 4 +- .../useTimeoutFn/stories/UseTimeoutFnDemo.vue | 17 +++-- .../useTimeoutFn/stories/useTimeoutFn.md | 16 +++-- .../useTimeoutFn/useTimeoutFn.spec.ts | 13 ++-- src/components/useTimeoutFn/useTimeoutFn.ts | 28 ++++----- src/vue-use-kit.ts | 1 + 17 files changed, 233 insertions(+), 66 deletions(-) create mode 100755 src/components/useIntervalFn/index.ts create mode 100755 src/components/useIntervalFn/stories/UseIntervalFnDemo.vue create mode 100755 src/components/useIntervalFn/stories/useIntervalFn.md create mode 100755 src/components/useIntervalFn/stories/useIntervalFn.story.ts create mode 100755 src/components/useIntervalFn/useIntervalFn.spec.ts create mode 100755 src/components/useIntervalFn/useIntervalFn.ts diff --git a/README.md b/README.md index 1973a64..f690cb8 100755 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ 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 + - [`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) - [`useRaf`](./src/components/useRaf/stories/useRaf.md) — returns `elapsedTime` with requestAnimationFrame. [![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/animations-useraf--demo) - [`useRafFn`](./src/components/useRafFn/stories/useRafFn.md) — calls function with requestAnimationFrame. diff --git a/src/components/useIntervalFn/index.ts b/src/components/useIntervalFn/index.ts new file mode 100755 index 0000000..3ad59a0 --- /dev/null +++ b/src/components/useIntervalFn/index.ts @@ -0,0 +1 @@ +export * from './useIntervalFn' diff --git a/src/components/useIntervalFn/stories/UseIntervalFnDemo.vue b/src/components/useIntervalFn/stories/UseIntervalFnDemo.vue new file mode 100755 index 0000000..8c4fd60 --- /dev/null +++ b/src/components/useIntervalFn/stories/UseIntervalFnDemo.vue @@ -0,0 +1,49 @@ + + + diff --git a/src/components/useIntervalFn/stories/useIntervalFn.md b/src/components/useIntervalFn/stories/useIntervalFn.md new file mode 100755 index 0000000..d716917 --- /dev/null +++ b/src/components/useIntervalFn/stories/useIntervalFn.md @@ -0,0 +1,63 @@ +# useIntervalFn + +Vue function that calls given callback repeatedly on a fixed time delay. + +## Reference + +```typescript +useIntervalFn( + callback: Function, + ms?: number, + runOnMount?: boolean +): { + isRunning: Ref; + start: () => void; + stop: () => void; + }; +``` + +### Parameters + +- `callback: Function` the function to call for each interval finishes +- `ms: number` how many milliseconds to wait before running the callback function +- `runOnMount: boolean` whether to run the interval on mount, `true` by default + +### Returns + +- `isRunning: Ref` this value is `true` if the interval is running, `false` otherwise +- `start: Function` the function used for starting the interval +- `stop: Function` the function used for stopping the interval + +## Usage + +```html + + + +``` diff --git a/src/components/useIntervalFn/stories/useIntervalFn.story.ts b/src/components/useIntervalFn/stories/useIntervalFn.story.ts new file mode 100755 index 0000000..229f916 --- /dev/null +++ b/src/components/useIntervalFn/stories/useIntervalFn.story.ts @@ -0,0 +1,28 @@ +import { storiesOf } from '@storybook/vue' +import path from 'path' +import StoryTitle from '@src/helpers/StoryTitle.vue' +import UseIntervalFnDemo from './UseIntervalFnDemo.vue' + +const functionName = 'useIntervalFn' +const functionPath = path.resolve(__dirname, '..') +const notes = require(`./${functionName}.md`).default + +const basicDemo = () => ({ + components: { StoryTitle, demo: UseIntervalFnDemo }, + template: ` +
+ + + + + +
` +}) + +storiesOf('animations|useIntervalFn', module) + .addParameters({ notes }) + .add('Demo', basicDemo) diff --git a/src/components/useIntervalFn/useIntervalFn.spec.ts b/src/components/useIntervalFn/useIntervalFn.spec.ts new file mode 100755 index 0000000..ab58c1c --- /dev/null +++ b/src/components/useIntervalFn/useIntervalFn.spec.ts @@ -0,0 +1,8 @@ +// import { mount } from '@src/helpers/test' +// import { useIntervalFn } from '@src/vue-use-kit' + +describe('useIntervalFn', () => { + it('should do something', () => { + // Add test here + }) +}) diff --git a/src/components/useIntervalFn/useIntervalFn.ts b/src/components/useIntervalFn/useIntervalFn.ts new file mode 100755 index 0000000..9390051 --- /dev/null +++ b/src/components/useIntervalFn/useIntervalFn.ts @@ -0,0 +1,23 @@ +import { onMounted, onUnmounted, ref } from '@src/api' + +export function useIntervalFn(callback: Function, ms = 0, runOnMount = true) { + const isRunning = ref(false) + let interval: any = null + + const start = () => { + if (interval) return + isRunning.value = true + interval = setInterval(callback, ms) + } + + const stop = () => { + clearInterval(interval) + isRunning.value = false + interval = null + } + + onMounted(() => runOnMount && start()) + onUnmounted(stop) + + return { isRunning, start, stop } +} diff --git a/src/components/useRaf/stories/UseRafDemo.vue b/src/components/useRaf/stories/UseRafDemo.vue index 398ab32..af5b144 100755 --- a/src/components/useRaf/stories/UseRafDemo.vue +++ b/src/components/useRaf/stories/UseRafDemo.vue @@ -42,15 +42,12 @@ import Vue from 'vue' import { ref, computed } from '@src/api' import { useRaf } from '@src/vue-use-kit' -const msToTime = (s: number) => { - const pad = (n: number, z = 2) => ('00' + n).slice(-z) - const ms = s % 1000 - s = (s - ms) / 1000 - const secs = s % 60 - s = (s - secs) / 60 - const mins = s % 60 - const hrs = (s - mins) / 60 - return `${pad(hrs)}:${pad(mins)}:${pad(secs)}.${pad(ms, 3)}` +const pad = (n: number) => (n < 10 ? '0' + n : n) +const msToTime = (duration: number) => { + const milliseconds = parseInt(`${(duration % 1000) / 10}`) + const seconds = Math.floor((duration / 1000) % 60) + const minutes = Math.floor((duration / (1000 * 60)) % 60) + return `${pad(minutes)}:${pad(seconds)}.${pad(milliseconds)}` } export default Vue.extend({ diff --git a/src/components/useTimeout/stories/UseTimeoutDemo.vue b/src/components/useTimeout/stories/UseTimeoutDemo.vue index f994538..1205c34 100755 --- a/src/components/useTimeout/stories/UseTimeoutDemo.vue +++ b/src/components/useTimeout/stories/UseTimeoutDemo.vue @@ -20,8 +20,8 @@ @click="start" v-text="btnResetMsg" /> - @@ -38,23 +38,22 @@ export default Vue.extend({ name: 'UseTimeoutDemo', setup() { const timerDuration = 3000 - const { isReady, isIdle, cancel, start } = useTimeout( + const { isReady, start, stop } = useTimeout( timerDuration, false ) const btnResetMsg = computed(() => { - return isIdle.value ? 'Start timer' : 'Reset Timer' + return isReady.value === null ? 'Start timer' : 'Reset Timer' }) const timerStatus = computed(() => { - if (isIdle.value) return 'Idle' if (isReady.value === false) return 'Pending...' - if (isReady.value === null) return 'Cancelled' + if (isReady.value === null) return 'Idle' return 'Completed' }) - return { btnResetMsg, timerStatus, cancel, start } + return { btnResetMsg, timerStatus, start, stop } } }) diff --git a/src/components/useTimeout/stories/useTimeout.md b/src/components/useTimeout/stories/useTimeout.md index 3e87ac7..4c75b43 100755 --- a/src/components/useTimeout/stories/useTimeout.md +++ b/src/components/useTimeout/stories/useTimeout.md @@ -10,9 +10,8 @@ useTimeout( runOnMount?: boolean ): { isReady: Ref; - isIdle: Ref; - cancel: () => void; start: () => void; + stop: () => void; } ``` @@ -26,10 +25,9 @@ useTimeout( - `isReady: Ref` the timer status - `false` when the timer is executing - `true` when the timer is completed - - `null` when the timer is cancelled -- `isIdle: Ref` this value is `true` if the timer has ever been called, `false` otherwise -- `cancel: Function` the function used to cancel the timer + - `null` when the timer is idle - `start: Function` the function used for starting or resetting the timer +- `stop: Function` the function used to stop the timer ## Usage @@ -39,7 +37,7 @@ useTimeout(

Timer status: {{ isReady ? 'Called!' : 'Pending...' }}

- + @@ -51,8 +49,8 @@ useTimeout( name: 'UseTimeoutDemo', setup() { const timerDuration = 3000 - const { isReady, cancel, start } = useTimeout(timerDuration) - return { isReady, cancel, start } + const { isReady, start, stop } = useTimeout(timerDuration) + return { isReady, start, stop } } }) diff --git a/src/components/useTimeout/useTimeout.spec.ts b/src/components/useTimeout/useTimeout.spec.ts index 4da7e2b..7aba14d 100755 --- a/src/components/useTimeout/useTimeout.spec.ts +++ b/src/components/useTimeout/useTimeout.spec.ts @@ -1,4 +1,5 @@ import { mount } from '@src/helpers/test' +import { computed } from '@src/api' import { useTimeout } from '@src/vue-use-kit' beforeEach(() => { @@ -17,7 +18,8 @@ const testComponent = () => ({ `, setup() { - const { isReady, isIdle } = useTimeout(1000) + const { isReady } = useTimeout(1000) + const isIdle = computed(() => isReady.value === null) return { isReady, isIdle } } }) diff --git a/src/components/useTimeout/useTimeout.ts b/src/components/useTimeout/useTimeout.ts index f80b07c..821e166 100755 --- a/src/components/useTimeout/useTimeout.ts +++ b/src/components/useTimeout/useTimeout.ts @@ -2,6 +2,6 @@ import { useTimeoutFn } from '@src/components/useTimeoutFn' const noop = () => null export function useTimeout(ms = 0, runOnMount = true) { - const { isReady, isIdle, cancel, start } = useTimeoutFn(noop, ms, runOnMount) - return { isReady, isIdle, cancel, start } + const { isReady, start, stop } = useTimeoutFn(noop, ms, runOnMount) + return { isReady, start, stop } } diff --git a/src/components/useTimeoutFn/stories/UseTimeoutFnDemo.vue b/src/components/useTimeoutFn/stories/UseTimeoutFnDemo.vue index d909a7a..fbdeeab 100755 --- a/src/components/useTimeoutFn/stories/UseTimeoutFnDemo.vue +++ b/src/components/useTimeoutFn/stories/UseTimeoutFnDemo.vue @@ -26,8 +26,8 @@ @click="start" v-text="btnResetMsg" /> - @@ -48,34 +48,33 @@ export default Vue.extend({ const timerHandler = () => { timerCallbackMsg.value = 'Timer completed!' } - const { isReady, isIdle, cancel, start } = useTimeoutFn( + const { isReady, start, stop } = useTimeoutFn( timerHandler, timerDuration, false ) const btnResetMsg = computed(() => { - return isIdle.value ? 'Start timer' : 'Reset Timer' + return isReady.value === null ? 'Start timer' : 'Reset Timer' }) const timerStatus = computed(() => { - if (isIdle.value) return 'Idle' if (isReady.value === false) return 'Pending...' - if (isReady.value === null) return 'Cancelled' + if (isReady.value === null) return 'Idle' return 'Completed' }) watch(isReady, newVal => { if (newVal === false) timerCallbackMsg.value = 'Timer not completed' - if (newVal === null) timerCallbackMsg.value = 'Timer cancelled!' + if (newVal === null) timerCallbackMsg.value = 'Timer stopped!' }) return { timerCallbackMsg, btnResetMsg, timerStatus, - cancel, - start + start, + stop } } }) diff --git a/src/components/useTimeoutFn/stories/useTimeoutFn.md b/src/components/useTimeoutFn/stories/useTimeoutFn.md index e6733c2..635f3dc 100755 --- a/src/components/useTimeoutFn/stories/useTimeoutFn.md +++ b/src/components/useTimeoutFn/stories/useTimeoutFn.md @@ -1,6 +1,6 @@ # useTimeoutFn -Vue function that calls given callback function after a specified `ms` amount of time. +Vue function that calls given callback after a specified `ms` amount of time. ## Reference @@ -11,9 +11,8 @@ useTimeoutFn( runOnMount?: boolean ): { isReady: Ref; - isIdle: Ref; - cancel: () => void; start: () => void; + stop: () => void; } ``` @@ -28,10 +27,9 @@ useTimeoutFn( - `isReady: Ref` the timer status - `false` when the timer is executing - `true` when the timer is completed - - `null` when the timer is cancelled -- `isIdle: Ref` this value is `true` if the timer has ever been called, `false` otherwise -- `cancel: Function` the function used to cancel the timer + - `null` when the timer is idle - `start: Function` the function used for starting or resetting the timer +- `stop: Function` the function used to stop the timer ## Usage @@ -42,7 +40,7 @@ useTimeoutFn(

Timeout Callback msg: {{ timerFnMsg }}

- + @@ -60,12 +58,12 @@ useTimeoutFn( timerFnMsg.value = 'Timer completed!' } - const { isReady, cancel, start } = useTimeoutFn( + const { isReady, start, stop } = useTimeoutFn( timerHandler, timerDuration ) - return { timerFnMsg, isReady, cancel, start } + return { timerFnMsg, isReady, start, stop } } }) diff --git a/src/components/useTimeoutFn/useTimeoutFn.spec.ts b/src/components/useTimeoutFn/useTimeoutFn.spec.ts index 28e171a..2372e65 100755 --- a/src/components/useTimeoutFn/useTimeoutFn.spec.ts +++ b/src/components/useTimeoutFn/useTimeoutFn.spec.ts @@ -1,5 +1,5 @@ import { mount } from '@src/helpers/test' -import { ref } from '@src/api' +import { ref, computed } from '@src/api' import { useTimeoutFn } from '@src/vue-use-kit' beforeEach(() => { @@ -15,7 +15,7 @@ const testComponent = (onMount = true) => ({
- +
@@ -23,14 +23,15 @@ const testComponent = (onMount = true) => ({ `, setup() { const isCallbackCalled = ref(false) - const { isReady, isIdle, cancel, start } = useTimeoutFn( + const { isReady, start, stop } = useTimeoutFn( () => { isCallbackCalled.value = true }, 1000, onMount ) - return { isReady, isIdle, cancel, start, isCallbackCalled } + const isIdle = computed(() => isReady.value === null) + return { isReady, isIdle, start, stop, isCallbackCalled } } }) @@ -53,14 +54,14 @@ describe('useTimeoutFn', () => { expect(setTimeout).toHaveBeenCalledTimes(2) }) - it('should hide all elements when cancel is called', async () => { + it('should hide all elements when stop is called', async () => { const wrapper = mount(testComponent()) jest.runAllTimers() // Wait for Vue to append #isReady in the DOM await wrapper.vm.$nextTick() expect(wrapper.find('#isReady').exists()).toBe(true) - wrapper.find('#cancel').trigger('click') + wrapper.find('#stop').trigger('click') jest.runAllTimers() // Wait for Vue to remove #isReady from the DOM diff --git a/src/components/useTimeoutFn/useTimeoutFn.ts b/src/components/useTimeoutFn/useTimeoutFn.ts index 2aa2479..48c21f0 100755 --- a/src/components/useTimeoutFn/useTimeoutFn.ts +++ b/src/components/useTimeoutFn/useTimeoutFn.ts @@ -1,21 +1,11 @@ import { onMounted, onUnmounted, ref } from '@src/api' export function useTimeoutFn(callback: Function, ms = 0, runOnMount = true) { - const isReady = ref(false) - const isIdle = ref(!runOnMount) + const isReady = ref(null) let timeout: any = null - const cancel = () => { - isReady.value = null - if (timeout) { - clearTimeout(timeout) - timeout = null - } - } - - const setTimer = () => { + const start = () => { isReady.value = false - if (isIdle.value) isIdle.value = false if (timeout) clearTimeout(timeout) timeout = setTimeout(() => { @@ -25,8 +15,16 @@ export function useTimeoutFn(callback: Function, ms = 0, runOnMount = true) { }, ms) } - onMounted(() => runOnMount && setTimer()) - onUnmounted(cancel) + const stop = () => { + isReady.value = null + if (timeout) { + clearTimeout(timeout) + timeout = null + } + } + + onMounted(() => runOnMount && start()) + onUnmounted(stop) - return { isReady, isIdle, cancel, start: setTimer } + return { isReady, start, stop } } diff --git a/src/vue-use-kit.ts b/src/vue-use-kit.ts index c7d9544..0f0c6d0 100755 --- a/src/vue-use-kit.ts +++ b/src/vue-use-kit.ts @@ -1,5 +1,6 @@ export * from './components/getQuery' export * from './components/useClickAway' +export * from './components/useIntervalFn' export * from './components/useMedia' export * from './components/useMouse' export * from './components/useMouseElement' From bb71f87f708b94fddc21906d62e44aa17c650697 Mon Sep 17 00:00:00 2001 From: Salvatore Tedde Date: Sat, 15 Feb 2020 12:52:59 +0000 Subject: [PATCH 2/2] feat(useInterval): Adding useInterval function --- README.md | 2 + src/components/useInterval/index.ts | 1 + .../useInterval/stories/UseIntervalDemo.vue | 41 ++++++++ .../useInterval/stories/useInterval.md | 58 +++++++++++ .../useInterval/stories/useInterval.story.ts | 28 ++++++ .../useInterval/useInterval.spec.ts | 33 +++++++ src/components/useInterval/useInterval.ts | 11 +++ .../useIntervalFn/useIntervalFn.spec.ts | 97 ++++++++++++++++++- src/components/useRaf/useRaf.spec.ts | 4 +- .../useRafFn/stories/UseRafFnAdvancedDemo.vue | 55 ++++++----- .../useRafFn/stories/useRafFn.story.ts | 2 +- src/components/useRafFn/useRafFn.spec.ts | 4 +- .../useTimeout/stories/UseTimeoutDemo.vue | 2 +- src/components/useTimeout/useTimeout.spec.ts | 2 +- .../useTimeoutFn/useTimeoutFn.spec.ts | 33 +++---- src/vue-use-kit.ts | 1 + 16 files changed, 320 insertions(+), 54 deletions(-) create mode 100755 src/components/useInterval/index.ts create mode 100755 src/components/useInterval/stories/UseIntervalDemo.vue create mode 100755 src/components/useInterval/stories/useInterval.md create mode 100755 src/components/useInterval/stories/useInterval.story.ts create mode 100755 src/components/useInterval/useInterval.spec.ts create mode 100755 src/components/useInterval/useInterval.ts diff --git a/README.md b/README.md index f690cb8..321620d 100755 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ 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. + [![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) - [`useRaf`](./src/components/useRaf/stories/useRaf.md) — returns `elapsedTime` with requestAnimationFrame. diff --git a/src/components/useInterval/index.ts b/src/components/useInterval/index.ts new file mode 100755 index 0000000..c617e4a --- /dev/null +++ b/src/components/useInterval/index.ts @@ -0,0 +1 @@ +export * from './useInterval' diff --git a/src/components/useInterval/stories/UseIntervalDemo.vue b/src/components/useInterval/stories/UseIntervalDemo.vue new file mode 100755 index 0000000..ec0a8d6 --- /dev/null +++ b/src/components/useInterval/stories/UseIntervalDemo.vue @@ -0,0 +1,41 @@ + + + diff --git a/src/components/useInterval/stories/useInterval.md b/src/components/useInterval/stories/useInterval.md new file mode 100755 index 0000000..40457b5 --- /dev/null +++ b/src/components/useInterval/stories/useInterval.md @@ -0,0 +1,58 @@ +# useInterval + +Vue function that updates the `counter` value repeatedly on a fixed time delay. + +## Reference + +```typescript +useInterval( + ms?: number, + runOnMount?: boolean +): { + isRunning: Ref; + counter: Ref; + start: () => void; + stop: () => void; + }; +``` + +### Parameters + +- `ms: number` how many milliseconds to wait before updating the counter +- `runOnMount: boolean` whether to run the interval on mount, `true` by default + +### Returns + +- `isRunning: Ref` this value is `true` if the interval is running, `false` otherwise +- `counter: Ref` the number of times the interval has run +- `start: Function` the function used for starting the interval +- `stop: Function` the function used for stopping the interval + +## Usage + +```html + + + +``` diff --git a/src/components/useInterval/stories/useInterval.story.ts b/src/components/useInterval/stories/useInterval.story.ts new file mode 100755 index 0000000..57511ec --- /dev/null +++ b/src/components/useInterval/stories/useInterval.story.ts @@ -0,0 +1,28 @@ +import { storiesOf } from '@storybook/vue' +import path from 'path' +import StoryTitle from '@src/helpers/StoryTitle.vue' +import UseIntervalDemo from './UseIntervalDemo.vue' + +const functionName = 'useInterval' +const functionPath = path.resolve(__dirname, '..') +const notes = require(`./${functionName}.md`).default + +const basicDemo = () => ({ + components: { StoryTitle, demo: UseIntervalDemo }, + template: ` +
+ + + + + +
` +}) + +storiesOf('animations|useInterval', module) + .addParameters({ notes }) + .add('Demo', basicDemo) diff --git a/src/components/useInterval/useInterval.spec.ts b/src/components/useInterval/useInterval.spec.ts new file mode 100755 index 0000000..b4b1cab --- /dev/null +++ b/src/components/useInterval/useInterval.spec.ts @@ -0,0 +1,33 @@ +import { mount } from '@src/helpers/test' +import { useInterval } from '@src/vue-use-kit' + +beforeEach(() => { + jest.useFakeTimers() +}) + +afterEach(() => { + jest.clearAllTimers() +}) + +const testComponent = () => ({ + template: ` +
+
+
+ `, + setup() { + const { isRunning } = useInterval(1000) + return { isRunning } + } +}) + +describe('useInterval', () => { + it('should show #isRunning when the intervals are called', async () => { + const wrapper = mount(testComponent()) + jest.advanceTimersByTime(1500) + + // Wait for Vue to append #isReady in the DOM + await wrapper.vm.$nextTick() + expect(wrapper.find('#isRunning').exists()).toBe(true) + }) +}) diff --git a/src/components/useInterval/useInterval.ts b/src/components/useInterval/useInterval.ts new file mode 100755 index 0000000..634f8eb --- /dev/null +++ b/src/components/useInterval/useInterval.ts @@ -0,0 +1,11 @@ +import { ref } from '@src/api' +import { useIntervalFn } from '@src/vue-use-kit' + +export function useInterval(ms = 0, runOnMount = true) { + const counter = ref(0) + const animHandler = () => { + counter.value = counter.value + 1 + } + const { isRunning, start, stop } = useIntervalFn(animHandler, ms, runOnMount) + return { isRunning, counter, start, stop } +} diff --git a/src/components/useIntervalFn/useIntervalFn.spec.ts b/src/components/useIntervalFn/useIntervalFn.spec.ts index ab58c1c..cbefc18 100755 --- a/src/components/useIntervalFn/useIntervalFn.spec.ts +++ b/src/components/useIntervalFn/useIntervalFn.spec.ts @@ -1,8 +1,97 @@ -// import { mount } from '@src/helpers/test' -// import { useIntervalFn } from '@src/vue-use-kit' +import { mount } from '@src/helpers/test' +import { ref } from '@src/api' +import { useIntervalFn } from '@src/vue-use-kit' + +beforeEach(() => { + jest.useFakeTimers() +}) + +afterEach(() => { + jest.clearAllTimers() +}) + +const testComponent = (onMount = true) => ({ + template: ` +
+
+
+ + +
+ `, + setup() { + const callbackCounter = ref(0) + const { isRunning, start, stop } = useIntervalFn( + () => { + callbackCounter.value = callbackCounter.value + 1 + }, + 1000, + onMount + ) + return { isRunning, start, stop, callbackCounter } + } +}) describe('useIntervalFn', () => { - it('should do something', () => { - // Add test here + it('should call setInterval when initialized', () => { + expect(setInterval).toHaveBeenCalledTimes(0) + mount(testComponent()) + jest.advanceTimersByTime(1500) + expect(setInterval).toHaveBeenCalled() + }) + + it('should call callback several times', async () => { + const wrapper = mount(testComponent()) + jest.advanceTimersByTime(25500) + await wrapper.vm.$nextTick() + expect(wrapper.find('#callbackCounter').text()).toBe('25') + }) + + it('should not show #isRunning when onMount is false', async () => { + const wrapper = mount(testComponent(false)) + jest.advanceTimersByTime(1500) + + // Wait for Vue rerender + await wrapper.vm.$nextTick() + expect(wrapper.find('#isRunning').exists()).toBe(false) + }) + + it('should show #isRunning when the intervals are called', async () => { + const wrapper = mount(testComponent()) + jest.advanceTimersByTime(1500) + + // Wait for Vue to append #isReady in the DOM + await wrapper.vm.$nextTick() + expect(wrapper.find('#isRunning').exists()).toBe(true) + }) + + it('should show #isRunning when start is called', async () => { + const wrapper = mount(testComponent(false)) + jest.advanceTimersByTime(1500) + + // Wait for Vue to append #isRunning in the DOM + await wrapper.vm.$nextTick() + expect(wrapper.find('#isRunning').exists()).toBe(false) + wrapper.find('#start').trigger('click') + jest.advanceTimersByTime(2500) + + // Wait for Vue to remove #isRunning from the DOM + await wrapper.vm.$nextTick() + expect(wrapper.find('#isRunning').exists()).toBe(true) + }) + + it('should hide #isRunning when stop is called', async () => { + const wrapper = mount(testComponent()) + jest.advanceTimersByTime(1500) + + // Wait for Vue to append #isRunning in the DOM + await wrapper.vm.$nextTick() + expect(wrapper.find('#isRunning').exists()).toBe(true) + wrapper.find('#stop').trigger('click') + jest.advanceTimersByTime(2500) + + // Wait for Vue to remove #isRunning from the DOM + await wrapper.vm.$nextTick() + expect(wrapper.find('#isRunning').exists()).toBe(false) }) }) diff --git a/src/components/useRaf/useRaf.spec.ts b/src/components/useRaf/useRaf.spec.ts index 688ca1e..2311a24 100755 --- a/src/components/useRaf/useRaf.spec.ts +++ b/src/components/useRaf/useRaf.spec.ts @@ -35,7 +35,7 @@ const testComponent = (onMount = false) => ({ }) describe('useRaf', () => { - it('should not display #isRunning when onMount is false', async () => { + it('should not show #isRunning when onMount is false', async () => { const wrapper = mount(testComponent(false)) await wrapper.vm.$nextTick() expect(rafSpy).not.toHaveBeenCalled() @@ -43,7 +43,7 @@ describe('useRaf', () => { expect(wrapper.find('#elapsed').text()).toBe('0') }) - it('should display #isRunning when onMount is true', async () => { + it('should show #isRunning when onMount is true', async () => { const wrapper = mount(testComponent(true)) await wrapper.vm.$nextTick() expect(rafSpy).toHaveBeenCalled() diff --git a/src/components/useRafFn/stories/UseRafFnAdvancedDemo.vue b/src/components/useRafFn/stories/UseRafFnAdvancedDemo.vue index 35116fd..b6ba40c 100755 --- a/src/components/useRafFn/stories/UseRafFnAdvancedDemo.vue +++ b/src/components/useRafFn/stories/UseRafFnAdvancedDemo.vue @@ -8,17 +8,18 @@
- - - -
@@ -36,15 +37,15 @@ import { ref, computed } from '@src/api' import { useRafFn } from '@src/vue-use-kit' const spriteOpts = { - w: 175 * 2, // Enlarge sprite 2x - h: 130 * 2, // Enlarge sprite 2x + w: 175, // Enlarge sprite 2x + h: 130, // Enlarge sprite 2x frames: 16 } export default Vue.extend({ name: 'UseRafFnAdvancedDemo', setup() { - const fps = ref(16) + const fps = ref(32) const spriteDirection = ref(-1) const spriteCurrentFrame = ref(0) @@ -52,36 +53,38 @@ export default Vue.extend({ const handleAnim = () => { // Get current frame spriteCurrentFrame.value = countFrame % spriteOpts.frames - countFrame = countFrame + 1 + countFrame = spriteDirection.value === 1 ? countFrame + 1 : countFrame - 1 } const spriteStyle = computed(() => { - const posX = - spriteOpts.w * spriteCurrentFrame.value * spriteDirection.value + const posX = spriteOpts.w * spriteCurrentFrame.value return { backgroundPosition: `${posX}px` } }) - const backward = () => { - spriteDirection.value = 1 - } - - const forward = () => { - spriteDirection.value = -1 + const invertDirection = () => { + spriteDirection.value = spriteDirection.value * -1 } const { isRunning, start, stop } = useRafFn(handleAnim, fps) - return { isRunning, start, stop, backward, forward, fps, spriteStyle } + return { isRunning, start, stop, fps, invertDirection, spriteStyle } } }) diff --git a/src/components/useRafFn/stories/useRafFn.story.ts b/src/components/useRafFn/stories/useRafFn.story.ts index de309e1..c6fb134 100755 --- a/src/components/useRafFn/stories/useRafFn.story.ts +++ b/src/components/useRafFn/stories/useRafFn.story.ts @@ -45,7 +45,7 @@ const advancedDemo = () => ({ Muybridge's work Horse in motion.

- You can play with the animation with the play, pause, forward and backward buttons. + You can play with the animation with the 'play', 'pause' and 'invert direction' buttons. You can also change the 'fps' value to make the horse run faster/slower.

diff --git a/src/components/useRafFn/useRafFn.spec.ts b/src/components/useRafFn/useRafFn.spec.ts index edf9d05..2ffde0a 100755 --- a/src/components/useRafFn/useRafFn.spec.ts +++ b/src/components/useRafFn/useRafFn.spec.ts @@ -45,7 +45,7 @@ const testComponent = (onMount = false) => ({ }) describe('useRafFn', () => { - it('should not display #isRunning when onMount is false', async () => { + it('should not show #isRunning when onMount is false', async () => { const wrapper = mount(testComponent(false)) await wrapper.vm.$nextTick() expect(rafSpy).not.toHaveBeenCalled() @@ -53,7 +53,7 @@ describe('useRafFn', () => { expect(wrapper.find('#elapsedTime').text()).toBe('0') }) - it('should display #isRunning when onMount is true', async () => { + it('should show #isRunning when onMount is true', async () => { const wrapper = mount(testComponent(true)) await wrapper.vm.$nextTick() expect(rafSpy).toHaveBeenCalled() diff --git a/src/components/useTimeout/stories/UseTimeoutDemo.vue b/src/components/useTimeout/stories/UseTimeoutDemo.vue index 1205c34..7a7c800 100755 --- a/src/components/useTimeout/stories/UseTimeoutDemo.vue +++ b/src/components/useTimeout/stories/UseTimeoutDemo.vue @@ -14,7 +14,7 @@ - + - -
-
+
+
+ +
`, setup() { @@ -54,7 +53,17 @@ describe('useTimeoutFn', () => { expect(setTimeout).toHaveBeenCalledTimes(2) }) - it('should hide all elements when stop is called', async () => { + it('should not show #isReady when onMount is false', async () => { + const wrapper = mount(testComponent(false)) + jest.runAllTimers() + + // Wait for Vue rerender + await wrapper.vm.$nextTick() + expect(wrapper.find('#isReady').exists()).toBe(false) + expect(wrapper.find('#isIdle').exists()).toBe(true) + }) + + it('should hide #isReady when stop is called', async () => { const wrapper = mount(testComponent()) jest.runAllTimers() @@ -69,7 +78,7 @@ describe('useTimeoutFn', () => { expect(wrapper.find('#isReady').exists()).toBe(false) }) - it('should display #isReady when the timers are called', async () => { + it('should show #isReady when the timers are called', async () => { const wrapper = mount(testComponent()) jest.runAllTimers() @@ -77,14 +86,4 @@ describe('useTimeoutFn', () => { await wrapper.vm.$nextTick() expect(wrapper.find('#isReady').exists()).toBe(true) }) - - it('should not display #isReady when onMount is false', async () => { - const wrapper = mount(testComponent(false)) - jest.runAllTimers() - - // Wait for Vue rerender - await wrapper.vm.$nextTick() - expect(wrapper.find('#isReady').exists()).toBe(false) - expect(wrapper.find('#isIdle').exists()).toBe(true) - }) }) diff --git a/src/vue-use-kit.ts b/src/vue-use-kit.ts index 0f0c6d0..4ede07a 100755 --- a/src/vue-use-kit.ts +++ b/src/vue-use-kit.ts @@ -1,6 +1,7 @@ export * from './components/getQuery' export * from './components/useClickAway' export * from './components/useIntervalFn' +export * from './components/useInterval' export * from './components/useMedia' export * from './components/useMouse' export * from './components/useMouseElement'