heartraite 1.0.213 → 1.0.215
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/enum/notification.enum.d.ts +2 -1
- package/dist/enum/notification.enum.js +1 -0
- package/dist/hooks/useTypewriter.d.ts +1 -0
- package/dist/hooks/useTypewriter.js +44 -37
- package/dist/hooks/useTypewriter.test.js +39 -0
- package/package.json +1 -1
- package/src/enum/notification.enum.ts +1 -0
- package/src/hooks/useTypewriter.test.ts +47 -0
- package/src/hooks/useTypewriter.ts +51 -41
|
@@ -6,4 +6,5 @@ var NotificationSetting;
|
|
|
6
6
|
NotificationSetting["NEW_MATCH"] = "new-match";
|
|
7
7
|
NotificationSetting["NEW_LIKE"] = "new-like";
|
|
8
8
|
NotificationSetting["NEW_MESSAGE"] = "new-message";
|
|
9
|
+
NotificationSetting["MATCH_SUGGESTION"] = "match-suggestion";
|
|
9
10
|
})(NotificationSetting || (exports.NotificationSetting = NotificationSetting = {}));
|
|
@@ -6,56 +6,63 @@ const useTypewriter = ({ text, typingSpeed = 50, initialDelay = 1000, blinkingSp
|
|
|
6
6
|
const [isComplete, setIsComplete] = (0, react_1.useState)(false);
|
|
7
7
|
const [displayedText, setDisplayedText] = (0, react_1.useState)("");
|
|
8
8
|
const [showDot, setShowDot] = (0, react_1.useState)(false);
|
|
9
|
+
const timersRef = (0, react_1.useRef)({ blinking: null, timeouts: new Set() });
|
|
10
|
+
const clearTimers = (0, react_1.useCallback)(() => {
|
|
11
|
+
const timers = timersRef.current;
|
|
12
|
+
if (timers.blinking)
|
|
13
|
+
clearInterval(timers.blinking);
|
|
14
|
+
timers.blinking = null;
|
|
15
|
+
timers.timeouts.forEach(clearTimeout);
|
|
16
|
+
timers.timeouts.clear();
|
|
17
|
+
}, []);
|
|
9
18
|
(0, react_1.useEffect)(() => {
|
|
10
19
|
if (!text || text.length === 0) {
|
|
11
|
-
setDisplayedText("");
|
|
12
|
-
setIsComplete(true);
|
|
13
|
-
setShowDot(false);
|
|
14
|
-
return;
|
|
20
|
+
setDisplayedText("");
|
|
21
|
+
setIsComplete(true);
|
|
22
|
+
setShowDot(false);
|
|
23
|
+
return;
|
|
15
24
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
const timers = timersRef.current;
|
|
26
|
+
const schedule = (fn, ms) => {
|
|
27
|
+
const id = setTimeout(() => {
|
|
28
|
+
timers.timeouts.delete(id);
|
|
29
|
+
fn();
|
|
30
|
+
}, ms);
|
|
31
|
+
timers.timeouts.add(id);
|
|
32
|
+
};
|
|
33
|
+
setDisplayedText("");
|
|
34
|
+
setShowDot(true);
|
|
35
|
+
setIsComplete(false);
|
|
36
|
+
timers.blinking = setInterval(() => {
|
|
24
37
|
setShowDot((prev) => !prev);
|
|
25
38
|
}, blinkingSpeed);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// Typing effect
|
|
33
|
-
let currentIndex = 0;
|
|
39
|
+
schedule(() => {
|
|
40
|
+
if (timers.blinking)
|
|
41
|
+
clearInterval(timers.blinking);
|
|
42
|
+
timers.blinking = null;
|
|
43
|
+
setShowDot(false);
|
|
44
|
+
let currentIndex = 1;
|
|
34
45
|
const typeNextChar = () => {
|
|
35
46
|
if (currentIndex < text.length) {
|
|
36
|
-
const charToAdd = text[currentIndex];
|
|
37
|
-
setDisplayedText((prev) => prev + charToAdd); // Append character
|
|
38
47
|
currentIndex++;
|
|
39
|
-
|
|
48
|
+
setDisplayedText(text.slice(0, currentIndex));
|
|
49
|
+
schedule(typeNextChar, typingSpeed);
|
|
40
50
|
}
|
|
41
51
|
else {
|
|
42
|
-
setIsComplete(true);
|
|
52
|
+
setIsComplete(true);
|
|
43
53
|
}
|
|
44
54
|
};
|
|
45
|
-
// Trigger the first character manually
|
|
46
55
|
setDisplayedText(text.charAt(0));
|
|
47
|
-
|
|
48
|
-
// Schedule the rest of the characters
|
|
49
|
-
setTimeout(typeNextChar, typingSpeed);
|
|
56
|
+
schedule(typeNextChar, typingSpeed);
|
|
50
57
|
}, initialDelay);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}, [text,
|
|
59
|
-
return { displayedText, showDot, isComplete };
|
|
58
|
+
return clearTimers;
|
|
59
|
+
}, [text, typingSpeed, initialDelay, blinkingSpeed, clearTimers]);
|
|
60
|
+
const revealAll = (0, react_1.useCallback)(() => {
|
|
61
|
+
clearTimers();
|
|
62
|
+
setDisplayedText(text ?? "");
|
|
63
|
+
setShowDot(false);
|
|
64
|
+
setIsComplete(true);
|
|
65
|
+
}, [text, clearTimers]);
|
|
66
|
+
return { displayedText, showDot, isComplete, revealAll };
|
|
60
67
|
};
|
|
61
68
|
exports.useTypewriter = useTypewriter;
|
|
@@ -68,4 +68,43 @@ describe("useTypewriter", () => {
|
|
|
68
68
|
});
|
|
69
69
|
expect(result.current.displayedText).toBe(sampleText.slice(0, 2));
|
|
70
70
|
});
|
|
71
|
+
it("reveals the full text immediately when revealAll is called mid-typing", () => {
|
|
72
|
+
const { result } = (0, react_1.renderHook)(() => (0, useTypewriter_1.useTypewriter)(defaultOptions));
|
|
73
|
+
(0, react_1.act)(() => {
|
|
74
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay + 100);
|
|
75
|
+
});
|
|
76
|
+
expect(result.current.isComplete).toBe(false);
|
|
77
|
+
(0, react_1.act)(() => {
|
|
78
|
+
result.current.revealAll();
|
|
79
|
+
});
|
|
80
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
81
|
+
expect(result.current.isComplete).toBe(true);
|
|
82
|
+
expect(result.current.showDot).toBe(false);
|
|
83
|
+
(0, react_1.act)(() => {
|
|
84
|
+
jest.advanceTimersByTime(sampleText.length * defaultOptions.typingSpeed);
|
|
85
|
+
});
|
|
86
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
87
|
+
});
|
|
88
|
+
it("reveals the full text when revealAll is called before typing starts", () => {
|
|
89
|
+
const { result } = (0, react_1.renderHook)(() => (0, useTypewriter_1.useTypewriter)(defaultOptions));
|
|
90
|
+
(0, react_1.act)(() => {
|
|
91
|
+
result.current.revealAll();
|
|
92
|
+
});
|
|
93
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
94
|
+
expect(result.current.isComplete).toBe(true);
|
|
95
|
+
expect(result.current.showDot).toBe(false);
|
|
96
|
+
(0, react_1.act)(() => {
|
|
97
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay * 2);
|
|
98
|
+
});
|
|
99
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
100
|
+
expect(result.current.showDot).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
it("stops all timers on unmount", () => {
|
|
103
|
+
const { unmount } = (0, react_1.renderHook)(() => (0, useTypewriter_1.useTypewriter)(defaultOptions));
|
|
104
|
+
(0, react_1.act)(() => {
|
|
105
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay + 100);
|
|
106
|
+
});
|
|
107
|
+
unmount();
|
|
108
|
+
expect(jest.getTimerCount()).toBe(0);
|
|
109
|
+
});
|
|
71
110
|
});
|
package/package.json
CHANGED
|
@@ -83,4 +83,51 @@ describe("useTypewriter", () => {
|
|
|
83
83
|
});
|
|
84
84
|
expect(result.current.displayedText).toBe(sampleText.slice(0, 2));
|
|
85
85
|
});
|
|
86
|
+
|
|
87
|
+
it("reveals the full text immediately when revealAll is called mid-typing", () => {
|
|
88
|
+
const { result } = renderHook(() => useTypewriter(defaultOptions));
|
|
89
|
+
|
|
90
|
+
act(() => {
|
|
91
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay + 100);
|
|
92
|
+
});
|
|
93
|
+
expect(result.current.isComplete).toBe(false);
|
|
94
|
+
|
|
95
|
+
act(() => {
|
|
96
|
+
result.current.revealAll();
|
|
97
|
+
});
|
|
98
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
99
|
+
expect(result.current.isComplete).toBe(true);
|
|
100
|
+
expect(result.current.showDot).toBe(false);
|
|
101
|
+
|
|
102
|
+
act(() => {
|
|
103
|
+
jest.advanceTimersByTime(sampleText.length * defaultOptions.typingSpeed);
|
|
104
|
+
});
|
|
105
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("reveals the full text when revealAll is called before typing starts", () => {
|
|
109
|
+
const { result } = renderHook(() => useTypewriter(defaultOptions));
|
|
110
|
+
|
|
111
|
+
act(() => {
|
|
112
|
+
result.current.revealAll();
|
|
113
|
+
});
|
|
114
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
115
|
+
expect(result.current.isComplete).toBe(true);
|
|
116
|
+
expect(result.current.showDot).toBe(false);
|
|
117
|
+
|
|
118
|
+
act(() => {
|
|
119
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay * 2);
|
|
120
|
+
});
|
|
121
|
+
expect(result.current.displayedText).toBe(sampleText);
|
|
122
|
+
expect(result.current.showDot).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("stops all timers on unmount", () => {
|
|
126
|
+
const { unmount } = renderHook(() => useTypewriter(defaultOptions));
|
|
127
|
+
act(() => {
|
|
128
|
+
jest.advanceTimersByTime(defaultOptions.initialDelay + 100);
|
|
129
|
+
});
|
|
130
|
+
unmount();
|
|
131
|
+
expect(jest.getTimerCount()).toBe(0);
|
|
132
|
+
});
|
|
86
133
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
3
|
interface UseTypewriterOptions {
|
|
4
4
|
text: string;
|
|
5
|
-
typingSpeed?: number;
|
|
6
|
-
initialDelay?: number;
|
|
7
|
-
blinkingSpeed?: number;
|
|
5
|
+
typingSpeed?: number;
|
|
6
|
+
initialDelay?: number;
|
|
7
|
+
blinkingSpeed?: number;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export const useTypewriter = ({
|
|
@@ -16,63 +16,73 @@ export const useTypewriter = ({
|
|
|
16
16
|
const [isComplete, setIsComplete] = useState(false);
|
|
17
17
|
const [displayedText, setDisplayedText] = useState("");
|
|
18
18
|
const [showDot, setShowDot] = useState(false);
|
|
19
|
+
const timersRef = useRef<{
|
|
20
|
+
blinking: ReturnType<typeof setInterval> | null;
|
|
21
|
+
timeouts: Set<ReturnType<typeof setTimeout>>;
|
|
22
|
+
}>({ blinking: null, timeouts: new Set() });
|
|
23
|
+
|
|
24
|
+
const clearTimers = useCallback(() => {
|
|
25
|
+
const timers = timersRef.current;
|
|
26
|
+
if (timers.blinking) clearInterval(timers.blinking);
|
|
27
|
+
timers.blinking = null;
|
|
28
|
+
timers.timeouts.forEach(clearTimeout);
|
|
29
|
+
timers.timeouts.clear();
|
|
30
|
+
}, []);
|
|
19
31
|
|
|
20
32
|
useEffect(() => {
|
|
21
33
|
if (!text || text.length === 0) {
|
|
22
|
-
setDisplayedText("");
|
|
23
|
-
setIsComplete(true);
|
|
24
|
-
setShowDot(false);
|
|
25
|
-
return;
|
|
34
|
+
setDisplayedText("");
|
|
35
|
+
setIsComplete(true);
|
|
36
|
+
setShowDot(false);
|
|
37
|
+
return;
|
|
26
38
|
}
|
|
27
39
|
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
const timers = timersRef.current;
|
|
41
|
+
const schedule = (fn: () => void, ms: number) => {
|
|
42
|
+
const id = setTimeout(() => {
|
|
43
|
+
timers.timeouts.delete(id);
|
|
44
|
+
fn();
|
|
45
|
+
}, ms);
|
|
46
|
+
timers.timeouts.add(id);
|
|
47
|
+
};
|
|
30
48
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
setIsComplete(false); // Reset completion flag
|
|
49
|
+
setDisplayedText("");
|
|
50
|
+
setShowDot(true);
|
|
51
|
+
setIsComplete(false);
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
blinkingInterval = setInterval(() => {
|
|
53
|
+
timers.blinking = setInterval(() => {
|
|
38
54
|
setShowDot((prev) => !prev);
|
|
39
55
|
}, blinkingSpeed);
|
|
40
56
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
setShowDot(false); // Hide blinking dot
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Typing effect
|
|
49
|
-
let currentIndex = 0;
|
|
57
|
+
schedule(() => {
|
|
58
|
+
if (timers.blinking) clearInterval(timers.blinking);
|
|
59
|
+
timers.blinking = null;
|
|
60
|
+
setShowDot(false);
|
|
50
61
|
|
|
62
|
+
let currentIndex = 1;
|
|
51
63
|
const typeNextChar = () => {
|
|
52
64
|
if (currentIndex < text.length) {
|
|
53
|
-
const charToAdd = text[currentIndex];
|
|
54
|
-
setDisplayedText((prev) => prev + charToAdd); // Append character
|
|
55
65
|
currentIndex++;
|
|
56
|
-
|
|
66
|
+
setDisplayedText(text.slice(0, currentIndex));
|
|
67
|
+
schedule(typeNextChar, typingSpeed);
|
|
57
68
|
} else {
|
|
58
|
-
setIsComplete(true);
|
|
69
|
+
setIsComplete(true);
|
|
59
70
|
}
|
|
60
71
|
};
|
|
61
72
|
|
|
62
|
-
// Trigger the first character manually
|
|
63
73
|
setDisplayedText(text.charAt(0));
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// Schedule the rest of the characters
|
|
67
|
-
setTimeout(typeNextChar, typingSpeed);
|
|
74
|
+
schedule(typeNextChar, typingSpeed);
|
|
68
75
|
}, initialDelay);
|
|
69
76
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
return clearTimers;
|
|
78
|
+
}, [text, typingSpeed, initialDelay, blinkingSpeed, clearTimers]);
|
|
79
|
+
|
|
80
|
+
const revealAll = useCallback(() => {
|
|
81
|
+
clearTimers();
|
|
82
|
+
setDisplayedText(text ?? "");
|
|
83
|
+
setShowDot(false);
|
|
84
|
+
setIsComplete(true);
|
|
85
|
+
}, [text, clearTimers]);
|
|
76
86
|
|
|
77
|
-
return { displayedText, showDot, isComplete };
|
|
87
|
+
return { displayedText, showDot, isComplete, revealAll };
|
|
78
88
|
};
|