rocket-cursor-component 1.0.5 → 1.0.7
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/rocket.Cursor.js +18 -14
- package/package.json +2 -6
- package/src/rocket.Cursor.tsx +26 -19
package/dist/rocket.Cursor.js
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
2
2
|
import React from "react";
|
|
3
3
|
const RocketCursor = ({ size = 50, threshold = 10, isVisible = true, }) => {
|
|
4
|
-
// Track cursor position
|
|
5
4
|
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
6
|
-
// Track rocket's rotation angle
|
|
7
5
|
const [angle, setAngle] = useState(0);
|
|
8
|
-
// Track if the cursor is moving
|
|
9
6
|
const [isMoving, setIsMoving] = useState(true);
|
|
10
|
-
|
|
7
|
+
const [visible, setVisible] = useState(isVisible);
|
|
11
8
|
const lastSignificantPosition = useRef({ x: 0, y: 0 });
|
|
12
9
|
const lastMoveTimestamp = useRef(Date.now());
|
|
13
|
-
// Update the position and angle when the mouse moves
|
|
14
10
|
const handleMouseMove = useCallback((e) => {
|
|
15
11
|
const currentPosition = { x: e.clientX, y: e.clientY };
|
|
16
12
|
setPosition(currentPosition);
|
|
17
|
-
// Calculate distance moved to decide if the rocket should rotate
|
|
18
13
|
const dx = currentPosition.x - lastSignificantPosition.current.x;
|
|
19
14
|
const dy = currentPosition.y - lastSignificantPosition.current.y;
|
|
20
15
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
21
|
-
// Rotate if the movement exceeds the threshold
|
|
22
16
|
if (distance > threshold) {
|
|
23
17
|
const newAngle = Math.atan2(dy, dx) * (180 / Math.PI) + 45;
|
|
24
18
|
setAngle(newAngle);
|
|
25
19
|
lastSignificantPosition.current = currentPosition;
|
|
26
20
|
}
|
|
27
|
-
// Mark as moving
|
|
28
21
|
lastMoveTimestamp.current = Date.now();
|
|
29
22
|
setIsMoving(true);
|
|
23
|
+
setVisible(true);
|
|
30
24
|
}, [threshold]);
|
|
31
|
-
|
|
25
|
+
const handleMouseOut = (e) => {
|
|
26
|
+
if (!e.relatedTarget ||
|
|
27
|
+
e.relatedTarget.nodeName === "HTML") {
|
|
28
|
+
setVisible(false);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const handleVisibilityChange = () => {
|
|
32
|
+
if (document.visibilityState === "visible") {
|
|
33
|
+
setVisible(true);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
32
36
|
useEffect(() => {
|
|
33
37
|
const checkIfStopped = () => {
|
|
34
38
|
const now = Date.now();
|
|
@@ -37,19 +41,19 @@ const RocketCursor = ({ size = 50, threshold = 10, isVisible = true, }) => {
|
|
|
37
41
|
}
|
|
38
42
|
};
|
|
39
43
|
const intervalId = setInterval(checkIfStopped, 100);
|
|
40
|
-
// Listen to mousemove events
|
|
41
44
|
window.addEventListener("mousemove", handleMouseMove);
|
|
42
|
-
|
|
45
|
+
document.addEventListener("mouseout", handleMouseOut);
|
|
46
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
43
47
|
return () => {
|
|
44
48
|
window.removeEventListener("mousemove", handleMouseMove);
|
|
49
|
+
document.removeEventListener("mouseout", handleMouseOut);
|
|
50
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
45
51
|
clearInterval(intervalId);
|
|
46
52
|
};
|
|
47
53
|
}, [handleMouseMove]);
|
|
48
|
-
|
|
49
|
-
if (!isVisible) {
|
|
54
|
+
if (!isVisible || !visible) {
|
|
50
55
|
return null;
|
|
51
56
|
}
|
|
52
|
-
// Render the rocket SVG at the cursor position with the correct rotation
|
|
53
57
|
return (React.createElement("div", { style: {
|
|
54
58
|
position: "fixed",
|
|
55
59
|
left: position.x,
|
package/package.json
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rocket-cursor-component",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "A customizable React component that replaces the cursor with an animated rocket.",
|
|
5
5
|
"main": "dist/rocket.Cursor.js",
|
|
6
6
|
"types": "dist/rocket.Cursor.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc"
|
|
9
9
|
},
|
|
10
|
-
"author": "
|
|
10
|
+
"author": "Tomas Dinh",
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"peerDependencies": {
|
|
13
|
-
"react": "^17.0.0"
|
|
14
|
-
},
|
|
15
12
|
"devDependencies": {
|
|
16
13
|
"@types/react": "^18.3.5",
|
|
17
14
|
"@types/react-dom": "^18.3.0",
|
|
18
|
-
"react": "^17.0.0",
|
|
19
15
|
"typescript": "^4.0.0"
|
|
20
16
|
},
|
|
21
17
|
"dependencies": {
|
package/src/rocket.Cursor.tsx
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
2
2
|
import React from "react";
|
|
3
3
|
|
|
4
|
-
// Props interface for customizing the size, rotation sensitivity, and visibility of the rocket cursor
|
|
5
4
|
interface RocketCursorProps {
|
|
6
|
-
size?: number;
|
|
7
|
-
threshold?: number;
|
|
8
|
-
isVisible?: boolean;
|
|
5
|
+
size?: number;
|
|
6
|
+
threshold?: number;
|
|
7
|
+
isVisible?: boolean;
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
const RocketCursor: React.FC<RocketCursorProps> = ({
|
|
@@ -13,43 +12,51 @@ const RocketCursor: React.FC<RocketCursorProps> = ({
|
|
|
13
12
|
threshold = 10,
|
|
14
13
|
isVisible = true,
|
|
15
14
|
}) => {
|
|
16
|
-
// Track cursor position
|
|
17
15
|
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
18
|
-
// Track rocket's rotation angle
|
|
19
16
|
const [angle, setAngle] = useState(0);
|
|
20
|
-
// Track if the cursor is moving
|
|
21
17
|
const [isMoving, setIsMoving] = useState(true);
|
|
22
|
-
|
|
23
|
-
// Store last significant cursor position to calculate movement
|
|
18
|
+
const [visible, setVisible] = useState(isVisible);
|
|
24
19
|
const lastSignificantPosition = useRef({ x: 0, y: 0 });
|
|
25
20
|
const lastMoveTimestamp = useRef(Date.now());
|
|
26
21
|
|
|
27
|
-
// Update the position and angle when the mouse moves
|
|
28
22
|
const handleMouseMove = useCallback(
|
|
29
23
|
(e: { clientX: any; clientY: any }) => {
|
|
30
24
|
const currentPosition = { x: e.clientX, y: e.clientY };
|
|
31
25
|
setPosition(currentPosition);
|
|
32
26
|
|
|
33
|
-
// Calculate distance moved to decide if the rocket should rotate
|
|
34
27
|
const dx = currentPosition.x - lastSignificantPosition.current.x;
|
|
35
28
|
const dy = currentPosition.y - lastSignificantPosition.current.y;
|
|
29
|
+
|
|
36
30
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
37
31
|
|
|
38
|
-
// Rotate if the movement exceeds the threshold
|
|
39
32
|
if (distance > threshold) {
|
|
40
33
|
const newAngle = Math.atan2(dy, dx) * (180 / Math.PI) + 45;
|
|
41
34
|
setAngle(newAngle);
|
|
42
35
|
lastSignificantPosition.current = currentPosition;
|
|
43
36
|
}
|
|
44
37
|
|
|
45
|
-
// Mark as moving
|
|
46
38
|
lastMoveTimestamp.current = Date.now();
|
|
47
39
|
setIsMoving(true);
|
|
40
|
+
setVisible(true);
|
|
48
41
|
},
|
|
49
42
|
[threshold]
|
|
50
43
|
);
|
|
51
44
|
|
|
52
|
-
|
|
45
|
+
const handleMouseOut = (e: MouseEvent) => {
|
|
46
|
+
if (
|
|
47
|
+
!e.relatedTarget ||
|
|
48
|
+
(e.relatedTarget as HTMLElement).nodeName === "HTML"
|
|
49
|
+
) {
|
|
50
|
+
setVisible(false);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handleVisibilityChange = () => {
|
|
55
|
+
if (document.visibilityState === "visible") {
|
|
56
|
+
setVisible(true);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
53
60
|
useEffect(() => {
|
|
54
61
|
const checkIfStopped = () => {
|
|
55
62
|
const now = Date.now();
|
|
@@ -60,22 +67,22 @@ const RocketCursor: React.FC<RocketCursorProps> = ({
|
|
|
60
67
|
|
|
61
68
|
const intervalId = setInterval(checkIfStopped, 100);
|
|
62
69
|
|
|
63
|
-
// Listen to mousemove events
|
|
64
70
|
window.addEventListener("mousemove", handleMouseMove);
|
|
71
|
+
document.addEventListener("mouseout", handleMouseOut);
|
|
72
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
65
73
|
|
|
66
|
-
// Cleanup event listeners on unmount
|
|
67
74
|
return () => {
|
|
68
75
|
window.removeEventListener("mousemove", handleMouseMove);
|
|
76
|
+
document.removeEventListener("mouseout", handleMouseOut);
|
|
77
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
69
78
|
clearInterval(intervalId);
|
|
70
79
|
};
|
|
71
80
|
}, [handleMouseMove]);
|
|
72
81
|
|
|
73
|
-
|
|
74
|
-
if (!isVisible) {
|
|
82
|
+
if (!isVisible || !visible) {
|
|
75
83
|
return null;
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
// Render the rocket SVG at the cursor position with the correct rotation
|
|
79
86
|
return (
|
|
80
87
|
<div
|
|
81
88
|
style={{
|