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.
@@ -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
- // Store last significant cursor position to calculate movement
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
- // Check if the cursor has stopped moving
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
- // Cleanup event listeners on unmount
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
- // Hide the rocket if not visible
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.5",
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": "Your Name",
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": {
@@ -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; // Rocket size (default is 50)
7
- threshold?: number; // Threshold for rotating the rocket (default is 10)
8
- isVisible?: boolean; // Control visibility of the rocket (default is true)
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
- // Check if the cursor has stopped moving
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
- // Hide the rocket if not visible
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={{