Skip to content

Commit 4eeacc8

Browse files
committed
main 🧊 add use vibrate
1 parent d351ef7 commit 4eeacc8

File tree

4 files changed

+60
-185
lines changed

4 files changed

+60
-185
lines changed

‎src/hooks/index.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,10 @@ export * from './useTimeout/useTimeout';
9999
export * from './useTimer/useTimer';
100100
export * from './useToggle/useToggle';
101101
export * from './useUnmount/useUnmount';
102+
export * from './useVibrate/useVibrate';
102103
export * from './useWebSocket/useWebSocket';
103104
export * from './useWindowEvent/useWindowEvent';
104105
export * from './useWindowFocus/useWindowFocus';
105106
export * from './useWindowScroll/useWindowScroll';
106107
export * from './useWindowSize/useWindowSize';
107-
export * from './useWizard/useWizard';
108+
export * from './useWizard/useWizard';

‎src/hooks/useVibrate/useVibrate.demo.tsx‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import { useVibrate } from './useVibrate';
22

33
const Demo = () => {
4-
const { isSupported, isVibrating, vibrate, stop } = useVibrate({
4+
const { vibrating, vibrate, stop } = useVibrate({
55
pattern: [300, 100, 200, 100, 1000, 300]
66
});
77

88
return (
9-
<div>
10-
<button type='button' disabled={!isSupported || isVibrating} onClick={() => vibrate()}>
11-
{isSupported ? 'Vibrate' : 'Web vibrate is not supported in your browser'}
9+
<>
10+
<p>Vibration is <code>{vibrating ? 'vibrating' : 'not vibrating'}</code></p>
11+
<button disabled={vibrating} type='button' onClick={() => vibrate()}>
12+
Vibrate
1213
</button>
13-
<button type='button' disabled={!isSupported} onClick={() => stop()}>
14+
<button type='button' onClick={stop}>
1415
Stop
1516
</button>
16-
</div>
17+
</>
1718
);
1819
};
1920

‎src/hooks/useVibrate/useVibrate.test.ts‎

Lines changed: 0 additions & 84 deletions
This file was deleted.
Lines changed: 51 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,35 @@
1-
import { useEffect, useState } from 'react';
1+
import { useEffect, useRef, useState } from 'react';
22

3-
import { isClient } from '@/utils/helpers';
3+
/** The use vibrate pattern type */
4+
export type UseVibratePattern = number | number[];
45

5-
/** The use vibration params */
6+
/** The use vibrate params type */
67
export interface UseVibrateParams {
8+
/** Time in milliseconds between vibrations */
9+
interval?: number;
710
/** Pattern for vibration */
8-
pattern: number | number[];
9-
/** Alternate way to enable vibration */
10-
enabled?: boolean;
11-
/** Indicates thar vibration will be endless */
12-
loop?: boolean;
11+
pattern: UseVibratePattern;
1312
}
1413

15-
/** The use vibration options */
16-
export interface UseVibrateOptions {
17-
/** Alternate way to enable vibration */
18-
enabled?: boolean;
19-
/** Indicates thar vibration will be endless */
20-
loop?: boolean;
21-
}
22-
23-
/** The use vibration return type */
14+
/** The use vibrate return type */
2415
export interface UseVibrateReturn {
25-
/** Indicates that the device supports Vibration API */
26-
isSupported: boolean;
27-
/** Indicates that the device is vibrating */
28-
isVibrating: boolean;
29-
/** Start vibration function */
30-
vibrate: (pattern?: number | number[]) => void;
31-
/** Stop vibration function */
16+
/** The support indicator */
17+
supported: boolean;
18+
/** The vibrating indicator */
19+
vibrating: boolean;
20+
/** The pause function */
21+
pause: () => void;
22+
/** The resume function */
23+
resume: () => void;
24+
/** The stop function */
3225
stop: () => void;
26+
/** The vibrate function */
27+
vibrate: (pattern?: UseVibratePattern) => void;
3328
}
3429

35-
export type UseVibrate = {
36-
(pattern: number | number[], options?: UseVibrateOptions): UseVibrateReturn;
37-
({ pattern, loop, enabled }: UseVibrateParams, options?: never): UseVibrateReturn;
38-
};
39-
40-
let interval: NodeJS.Timeout;
4130
/**
4231
* @name useVibrate
43-
* @description - Hook that provides Vibrate API
32+
* @description - Hook that provides vibrate api
4433
* @category Browser
4534
*
4635
* @overload
@@ -50,80 +39,48 @@ let interval: NodeJS.Timeout;
5039
* @returns {UseVibrateReturn} An object containing support indicator, start vibration and stop vibration functions
5140
*
5241
* @example
53-
* const { isSupported, isVibrating, vibrate, stop } = useVibrate(1000);
54-
*
55-
* @overload
56-
* @param {(number|number[])} params.pattern Pattern for vibration
57-
* @param {boolean} [params.loop] Indicates thar vibration will be endless
58-
* @param {boolean} [params.enabled] Alternate way to enable vibration
59-
* @returns {UseVibrateReturn} An object containing support indicator, vibrating indicator, start vibration and stop vibration functions
60-
*
61-
* @example
62-
* const { isSupported, isVibrating, vibrate, stop } = useVibrate({pattern: [200, 100, 200], loop: true});
63-
* */
64-
export const useVibrate: UseVibrate = (...params) => {
65-
const pattern =
66-
typeof params[0] === 'number' || Array.isArray(params[0]) ? params[0] : params[0]?.pattern;
67-
const { loop, enabled } =
68-
typeof params[0] === 'number' || Array.isArray(params[0]) ? params[1] ?? {} : params[0] ?? {};
69-
70-
const [isSupported, setIsSupported] = useState(false);
71-
const [isVibrating, setIsVibrating] = useState(false);
72-
73-
useEffect(() => {
74-
if (isClient && navigator && 'vibrate' in navigator) {
75-
setIsSupported(true);
76-
}
77-
}, []);
78-
79-
const vibrate = (curPattern = pattern) => {
80-
if (!isSupported || isVibrating) return;
81-
82-
const duration = Array.isArray(curPattern) ? curPattern.reduce((a, b) => a + b) : curPattern;
83-
84-
setIsVibrating(true);
85-
navigator.vibrate(curPattern);
86-
87-
if (loop) {
88-
interval = setInterval(() => {
89-
navigator.vibrate(curPattern);
90-
}, duration);
91-
} else {
92-
setTimeout(() => {
93-
setIsVibrating(false);
94-
}, duration);
95-
}
42+
* const { supported, vibrating, vibrate, stop } = useVibrate(1000);
43+
*/
44+
export const useVibrate = (params: UseVibrateParams) => {
45+
const supported = typeof navigator !== 'undefined' && 'vibrate' in navigator;
46+
47+
const interval = params.interval ?? 0;
48+
const intervalIdRef = useRef<ReturnType<typeof setInterval>>();
49+
const [vibrating, setVibrating] = useState(false);
50+
51+
const vibrate = (pattern: UseVibratePattern = params.pattern) => {
52+
if (!supported) return;
53+
navigator.vibrate(pattern);
54+
setVibrating(true);
9655
};
9756

9857
const stop = () => {
99-
if (!isSupported) return;
58+
if (!supported) return;
10059

101-
setIsVibrating(false);
60+
setVibrating(false);
10261
navigator.vibrate(0);
10362

104-
if (loop) {
105-
clearInterval(interval);
106-
}
63+
if (intervalIdRef.current) clearInterval(intervalIdRef.current);
10764
};
10865

109-
useEffect(() => {
110-
if (!isSupported || isVibrating) return;
66+
const pause = () => {
67+
if (!supported) return;
68+
if (intervalIdRef.current) clearInterval(intervalIdRef.current);
69+
};
11170

112-
if (enabled) {
113-
vibrate();
114-
}
71+
const resume = () => {
72+
if (!supported) return;
73+
if (intervalIdRef.current) clearInterval(intervalIdRef.current);
74+
intervalIdRef.current = setInterval(vibrate, interval);
75+
};
11576

77+
useEffect(() => {
78+
if (!supported || typeof params.interval === 'undefined') return;
79+
intervalIdRef.current = setInterval(vibrate, interval);
11680
return () => {
117-
if (enabled) {
118-
setIsVibrating(false);
119-
navigator.vibrate(0);
120-
121-
if (loop) {
122-
clearInterval(interval);
123-
}
124-
}
81+
clearInterval(intervalIdRef.current);
12582
};
126-
}, [enabled]);
83+
}, [params.interval, params.pattern]);
12784

128-
return { isSupported, vibrate, stop, isVibrating } as const;
85+
return { supported, vibrate, stop, vibrating, pause, resume };
12986
};

0 commit comments

Comments
 (0)