Skip to content

Commit b6e9d40

Browse files
committed
feat: Added useTimeout function
1 parent 44681a1 commit b6e9d40

File tree

11 files changed

+264
-39
lines changed

11 files changed

+264
-39
lines changed

src/components/useTimeout/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './useTimeout'
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<template>
2+
<table class="table is-fullwidth">
3+
<thead>
4+
<tr>
5+
<th>Prop</th>
6+
<th>Value</th>
7+
</tr>
8+
</thead>
9+
<tbody>
10+
<tr>
11+
<td>timerStatus</td>
12+
<td>
13+
<span>{{ timerStatus }}</span>
14+
</td>
15+
</tr>
16+
<tr>
17+
<td colspan="3">
18+
<button
19+
class="button is-primary"
20+
@click="resetTimer"
21+
v-text="btnResetMsg"
22+
/>
23+
<button class="button is-danger" @click="cancelTimer">
24+
Cancel Timer
25+
</button>
26+
</td>
27+
</tr>
28+
</tbody>
29+
</table>
30+
</template>
31+
32+
<script lang="ts">
33+
import Vue from 'vue'
34+
import { computed, ref } from '../../../api'
35+
import { useTimeout } from '../../../vue-use-kit'
36+
37+
export default Vue.extend({
38+
name: 'UseTimeoutDemo',
39+
setup() {
40+
const timerDuration = 3000
41+
const { isReady, isIdle, cancelTimer, resetTimer } = useTimeout(
42+
timerDuration,
43+
false
44+
)
45+
46+
const btnResetMsg = computed(() => {
47+
return isIdle.value ? 'Start timer' : 'Reset Timer'
48+
})
49+
50+
const timerStatus = computed(() => {
51+
if (isIdle.value) return 'Idle'
52+
if (isReady.value === false) return 'Pending...'
53+
if (isReady.value === null) return 'Cancelled'
54+
return 'Completed'
55+
})
56+
57+
return { btnResetMsg, timerStatus, cancelTimer, resetTimer }
58+
}
59+
})
60+
</script>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# useTimeout
2+
3+
Vue function that returns `isReady` value as `true` after a specified `ms` amount of time.
4+
5+
## Reference
6+
7+
```typescript
8+
useTimeout(
9+
ms?: number,
10+
runOnMount?: boolean
11+
): {
12+
isReady: Ref<boolean | null>;
13+
isIdle: Ref<boolean>;
14+
cancelTimer: () => void;
15+
resetTimer: () => void;
16+
}
17+
```
18+
19+
### Parameters
20+
21+
- `ms: number` how many milliseconds to wait before the timer is completed
22+
- `runOnMount: boolean` whether to run the timeout on mount, `true` by default
23+
24+
### Returns
25+
26+
- `isReady: boolean | null` the timer status
27+
- `false` when the timer is executing
28+
- `true` when the timer is completed
29+
- `null` when the timer is cancelled
30+
- `isIdle: boolean` this value is `true` if the timer has ever been called, `false` otherwise
31+
- `cancelTimer: Function` the function used to cancel the timer
32+
- `resetTimer: Function` the function used for resetting the timer
33+
34+
## Usage
35+
36+
```html
37+
<template>
38+
<div>
39+
<p>Timer status: {{ isReady ? 'Called!' : 'Pending...' }}</p>
40+
41+
<button @click="resetTimer">Reset Timer</button>
42+
<button @click="cancelTimer">Cancel Timer</button>
43+
</div>
44+
</template>
45+
46+
<script lang="ts">
47+
import Vue from 'vue'
48+
import { useTimeout } from 'vue-use-kit'
49+
50+
export default Vue.extend({
51+
name: 'UseTimeoutDemo',
52+
setup() {
53+
const timerDuration = 3000
54+
const { isReady, cancelTimer, resetTimer } = useTimeout(timerDuration)
55+
return { isReady, cancelTimer, resetTimer }
56+
}
57+
})
58+
</script>
59+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { storiesOf } from '@storybook/vue'
2+
import StoryTitle from '../../../helpers/StoryTitle.vue'
3+
import UseTimeoutDemo from './UseTimeoutDemo.vue'
4+
5+
const storiesPath = __dirname
6+
const notes = require('./useTimeout.md').default
7+
8+
const basicDemo = () => ({
9+
components: { StoryTitle, demo: UseTimeoutDemo },
10+
template: `
11+
<div class="container">
12+
<story-title stories-path="${storiesPath}" file-name="UseTimeoutDemo.vue">
13+
<template v-slot:title></template>
14+
<template v-slot:intro></template>
15+
</story-title>
16+
<demo />
17+
</div>`
18+
})
19+
20+
storiesOf('animations|useTimeout', module)
21+
.addParameters({ notes })
22+
.add('Demo', basicDemo)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { mount } from '../../helpers/test'
2+
import { useTimeout } from '../../vue-use-kit'
3+
4+
beforeEach(() => {
5+
jest.useFakeTimers()
6+
})
7+
8+
afterEach(() => {
9+
jest.clearAllTimers()
10+
})
11+
12+
const testComponent = () => ({
13+
template: `
14+
<div>
15+
<div id="isIdle" v-if="isIdle"></div>
16+
<div id="isReady" v-if="isReady"></div>
17+
</div>
18+
`,
19+
setup() {
20+
const { isReady, isIdle } = useTimeout(1000)
21+
return { isReady, isIdle }
22+
}
23+
})
24+
25+
describe('useTimeout', () => {
26+
it('should display #isReady when the timers are called, but not #isIdle', async () => {
27+
const wrapper = mount(testComponent())
28+
jest.runAllTimers()
29+
30+
// Wait for Vue to append #isReady in the DOM
31+
await wrapper.vm.$nextTick()
32+
expect(wrapper.find('#isReady').exists()).toBe(true)
33+
expect(wrapper.find('#isIdle').exists()).toBe(false)
34+
})
35+
})
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useTimeoutFn } from '../../vue-use-kit'
2+
3+
const noop = () => null
4+
export function useTimeout(ms = 0, runOnMount = true) {
5+
const { isReady, isIdle, cancelTimer, resetTimer } = useTimeoutFn(
6+
noop,
7+
ms,
8+
runOnMount
9+
)
10+
return { isReady, isIdle, cancelTimer, resetTimer }
11+
}

src/components/useTimeoutFn/stories/UseTimeoutFnDemo.vue

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,33 @@
33
<thead>
44
<tr>
55
<th>Prop</th>
6-
<th>Description</th>
7-
<th>Message</th>
6+
<th>Value</th>
87
</tr>
98
</thead>
109
<tbody>
1110
<tr>
12-
<td>isReadyStatus</td>
13-
<td>Timeout status</td>
11+
<td>timerStatus</td>
1412
<td>
15-
<span>{{ isReadyStatus }}</span>
13+
<span>{{ timerStatus }}</span>
1614
</td>
1715
</tr>
1816
<tr>
19-
<td>timerFnMsg</td>
20-
<td>Timer function callback message</td>
17+
<td>timerCallbackMsg</td>
2118
<td>
22-
<span>{{ timerFnMsg }}</span>
19+
<span>{{ timerCallbackMsg }}</span>
2320
</td>
2421
</tr>
2522
<tr>
26-
<td>
27-
<button class="button is-primary" @click="resetTimer">
28-
Reset Timer
29-
</button>
23+
<td colspan="3">
24+
<button
25+
class="button is-primary"
26+
@click="resetTimer"
27+
v-text="btnResetMsg"
28+
/>
3029
<button class="button is-danger" @click="cancelTimer">
3130
Cancel Timer
3231
</button>
3332
</td>
34-
<td></td>
3533
</tr>
3634
</tbody>
3735
</table>
@@ -45,28 +43,40 @@ import { useTimeoutFn } from '../../../vue-use-kit'
4543
export default Vue.extend({
4644
name: 'UseTimeoutFnDemo',
4745
setup() {
48-
const timerFnMsg = ref('Timer not completed')
46+
const timerCallbackMsg = ref('Timer not completed')
4947
const timerDuration = 3000
5048
const timerHandler = () => {
51-
timerFnMsg.value = 'Timer completed!'
49+
timerCallbackMsg.value = 'Timer completed!'
5250
}
53-
const { isReady, cancelTimer, resetTimer } = useTimeoutFn(
51+
const { isReady, isIdle, cancelTimer, resetTimer } = useTimeoutFn(
5452
timerHandler,
55-
timerDuration
53+
timerDuration,
54+
false
5655
)
5756
58-
const isReadyStatus = computed(() => {
57+
const btnResetMsg = computed(() => {
58+
return isIdle.value ? 'Start timer' : 'Reset Timer'
59+
})
60+
61+
const timerStatus = computed(() => {
62+
if (isIdle.value) return 'Idle'
5963
if (isReady.value === false) return 'Pending...'
6064
if (isReady.value === null) return 'Cancelled'
61-
return 'Called!'
65+
return 'Completed'
6266
})
6367
6468
watch(isReady, newVal => {
65-
if (newVal === false) timerFnMsg.value = 'Timer not completed'
66-
if (newVal === null) timerFnMsg.value = 'Timer cancelled!'
69+
if (newVal === false) timerCallbackMsg.value = 'Timer not completed'
70+
if (newVal === null) timerCallbackMsg.value = 'Timer cancelled!'
6771
})
6872
69-
return { timerFnMsg, isReadyStatus, cancelTimer, resetTimer }
73+
return {
74+
timerCallbackMsg,
75+
btnResetMsg,
76+
timerStatus,
77+
cancelTimer,
78+
resetTimer
79+
}
7080
}
7181
})
7282
</script>

src/components/useTimeoutFn/stories/useTimeoutFn.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
# useTimeoutFn
22

3-
Vue function that calls given callback function after a specified amount of milliseconds.
3+
Vue function that calls given callback function after a specified `ms` amount of time.
44

55
## Reference
66

77
```typescript
88
useTimeoutFn(
99
callback: Function,
10-
ms?: number
10+
ms?: number,
11+
runOnMount?: boolean
1112
): {
1213
isReady: Ref<boolean | null>;
14+
isIdle: Ref<boolean>;
1315
cancelTimer: () => void;
1416
resetTimer: () => void;
1517
}
@@ -19,19 +21,24 @@ useTimeoutFn(
1921

2022
- `callback: Function` the function to call when the timer finishes
2123
- `ms: number` how many milliseconds to wait before running the callback function
24+
- `runOnMount: boolean` whether to run the timeout on mount, `true` by default
2225

2326
### Returns
2427

2528
- `isReady: boolean | null` the timer status
26-
- `cancelTimer: Function` the function used for canceling the timer
29+
- `false` when the timer is executing
30+
- `true` when the timer is completed
31+
- `null` when the timer is cancelled
32+
- `isIdle: boolean` this value is `true` if the timer has ever been called, `false` otherwise
33+
- `cancelTimer: Function` the function used to cancel the timer
2734
- `resetTimer: Function` the function used for resetting the timer
2835

2936
## Usage
3037

3138
```html
3239
<template>
3340
<div>
34-
<p>Timeout status: {{ isReady ? 'Called!' : 'Pending...' }}</p>
41+
<p>Timer status: {{ isReady ? 'Called!' : 'Pending...' }}</p>
3542
<p>Timeout Callback msg: {{ timerFnMsg }}</p>
3643

3744
<button @click="resetTimer">Reset Timer</button>

0 commit comments

Comments
 (0)