@webenza/ui 0.0.1 → 0.0.3

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/index.js CHANGED
@@ -13,7 +13,7 @@ var CursorFollower = ({
13
13
  text = "PLAY",
14
14
  size = 90,
15
15
  borderWidth = 2,
16
- borderColor = "#fff",
16
+ borderColor = "#ffffff",
17
17
  background = "transparent",
18
18
  fontFamily = "inherit",
19
19
  fontSize = 12,
@@ -23,11 +23,11 @@ var CursorFollower = ({
23
23
  showScale = 1,
24
24
  hideScale = 0,
25
25
  enabled = true,
26
- blockSelectors = [],
26
+ blockSelectors = ["button", "a"],
27
27
  containerRef
28
28
  }) => {
29
29
  const cursorRef = react.useRef(null);
30
- react.useEffect(() => {
30
+ react.useLayoutEffect(() => {
31
31
  if (!enabled) return;
32
32
  const cursor = cursorRef.current;
33
33
  if (!cursor) return;
@@ -56,6 +56,9 @@ var CursorFollower = ({
56
56
  targetX = e.clientX;
57
57
  targetY = e.clientY;
58
58
  }
59
+ if (!visible && !blocked) {
60
+ show();
61
+ }
59
62
  };
60
63
  const update = () => {
61
64
  currentX += (targetX - currentX) * lerp;
@@ -70,31 +73,49 @@ var CursorFollower = ({
70
73
  target.addEventListener("mouseenter", show);
71
74
  target.addEventListener("mouseleave", hide);
72
75
  gsap__default.default.ticker.add(update);
73
- const unbinds = blockSelectors.map((selector) => {
74
- const el = document.querySelector(selector);
75
- if (!el) return () => {
76
- };
77
- const enter = () => {
78
- blocked = true;
79
- hide();
80
- };
81
- const leave = () => {
82
- blocked = false;
83
- show();
84
- };
85
- el.addEventListener("mouseenter", enter);
86
- el.addEventListener("mouseleave", leave);
87
- return () => {
88
- el.removeEventListener("mouseenter", enter);
89
- el.removeEventListener("mouseleave", leave);
90
- };
76
+ requestAnimationFrame(() => {
77
+ if (containerRef?.current) {
78
+ const bounds = containerRef.current.getBoundingClientRect();
79
+ targetX = bounds.width / 2;
80
+ targetY = bounds.height / 2;
81
+ } else {
82
+ targetX = window.innerWidth / 2;
83
+ targetY = window.innerHeight / 2;
84
+ }
85
+ currentX = targetX;
86
+ currentY = targetY;
87
+ gsap__default.default.set(cursor, {
88
+ x: currentX - size / 2,
89
+ y: currentY - size / 2
90
+ });
91
+ show();
92
+ });
93
+ const cleanupFns = [];
94
+ blockSelectors.forEach((selector) => {
95
+ const elements = document.querySelectorAll(selector);
96
+ elements.forEach((el) => {
97
+ const enter = () => {
98
+ blocked = true;
99
+ hide();
100
+ };
101
+ const leave = () => {
102
+ blocked = false;
103
+ show();
104
+ };
105
+ el.addEventListener("mouseenter", enter);
106
+ el.addEventListener("mouseleave", leave);
107
+ cleanupFns.push(() => {
108
+ el.removeEventListener("mouseenter", enter);
109
+ el.removeEventListener("mouseleave", leave);
110
+ });
111
+ });
91
112
  });
92
113
  return () => {
93
114
  target.removeEventListener("mousemove", move);
94
115
  target.removeEventListener("mouseenter", show);
95
116
  target.removeEventListener("mouseleave", hide);
96
117
  gsap__default.default.ticker.remove(update);
97
- unbinds.forEach((u) => u());
118
+ cleanupFns.forEach((fn) => fn());
98
119
  };
99
120
  }, [
100
121
  enabled,
@@ -102,7 +123,8 @@ var CursorFollower = ({
102
123
  lerp,
103
124
  showScale,
104
125
  hideScale,
105
- blockSelectors,
126
+ // Stabilize dependency: only re-run if the joined string changes
127
+ blockSelectors.join(","),
106
128
  containerRef
107
129
  ]);
108
130
  if (!enabled) return null;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cursor/CursorFollower/CursorFollower.tsx"],"names":["useRef","useEffect","gsap","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, useRef } from \"react\";\r\nimport gsap from \"gsap\";\r\n\r\nexport type CursorFollowerProps = {\r\n text?: string;\r\n\r\n size?: number;\r\n borderWidth?: number;\r\n borderColor?: string;\r\n background?: string;\r\n\r\n fontFamily?: string;\r\n fontSize?: number;\r\n fontWeight?: number | string;\r\n letterSpacing?: number;\r\n\r\n lerp?: number;\r\n showScale?: number;\r\n hideScale?: number;\r\n\r\n enabled?: boolean;\r\n blockSelectors?: string[];\r\n containerRef?: React.RefObject<HTMLElement>;\r\n};\r\n\r\nexport const CursorFollower = ({\r\n text = \"PLAY\",\r\n\r\n size = 90,\r\n borderWidth = 2,\r\n borderColor = \"#fff\",\r\n background = \"transparent\",\r\n\r\n fontFamily = \"inherit\",\r\n fontSize = 12,\r\n fontWeight = 400,\r\n letterSpacing = 2,\r\n\r\n lerp = 0.035,\r\n showScale = 1,\r\n hideScale = 0,\r\n\r\n enabled = true,\r\n blockSelectors = [],\r\n containerRef,\r\n}: CursorFollowerProps) => {\r\n const cursorRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n if (!enabled) return;\r\n\r\n const cursor = cursorRef.current;\r\n if (!cursor) return;\r\n\r\n let targetX = 0;\r\n let targetY = 0;\r\n let currentX = 0;\r\n let currentY = 0;\r\n let visible = false;\r\n let blocked = false;\r\n\r\n const show = () => {\r\n if (visible || blocked) return;\r\n visible = true;\r\n gsap.to(cursor, { scale: showScale, opacity: 1, duration: 0.25 });\r\n };\r\n\r\n const hide = () => {\r\n if (!visible) return;\r\n visible = false;\r\n gsap.to(cursor, { scale: hideScale, opacity: 0, duration: 0.25 });\r\n };\r\n\r\n const move = (e: MouseEvent) => {\r\n if (containerRef?.current) {\r\n const bounds = containerRef.current.getBoundingClientRect();\r\n // Calculate relative coordinates\r\n targetX = e.clientX - bounds.left;\r\n targetY = e.clientY - bounds.top;\r\n } else {\r\n targetX = e.clientX;\r\n targetY = e.clientY;\r\n }\r\n };\r\n\r\n const update = () => {\r\n currentX += (targetX - currentX) * lerp;\r\n currentY += (targetY - currentY) * lerp;\r\n\r\n gsap.set(cursor, {\r\n x: currentX - size / 2,\r\n y: currentY - size / 2,\r\n });\r\n };\r\n\r\n // Event Listeners Source\r\n const target = containerRef?.current || window;\r\n\r\n target.addEventListener(\"mousemove\", move as any);\r\n target.addEventListener(\"mouseenter\", show as any);\r\n target.addEventListener(\"mouseleave\", hide as any);\r\n\r\n gsap.ticker.add(update);\r\n\r\n const unbinds = blockSelectors.map((selector) => {\r\n const el = document.querySelector(selector);\r\n if (!el) return () => { };\r\n\r\n const enter = () => {\r\n blocked = true;\r\n hide();\r\n };\r\n const leave = () => {\r\n blocked = false;\r\n show();\r\n };\r\n\r\n el.addEventListener(\"mouseenter\", enter);\r\n el.addEventListener(\"mouseleave\", leave);\r\n\r\n return () => {\r\n el.removeEventListener(\"mouseenter\", enter);\r\n el.removeEventListener(\"mouseleave\", leave);\r\n };\r\n });\r\n\r\n return () => {\r\n target.removeEventListener(\"mousemove\", move as any);\r\n target.removeEventListener(\"mouseenter\", show as any);\r\n target.removeEventListener(\"mouseleave\", hide as any);\r\n gsap.ticker.remove(update);\r\n unbinds.forEach((u) => u());\r\n };\r\n }, [\r\n enabled,\r\n size,\r\n lerp,\r\n showScale,\r\n hideScale,\r\n blockSelectors,\r\n containerRef\r\n ]);\r\n\r\n if (!enabled) return null;\r\n\r\n return (\r\n <div\r\n ref={cursorRef}\r\n style={{\r\n position: containerRef ? \"absolute\" : \"fixed\",\r\n top: 0,\r\n left: 0,\r\n width: size,\r\n height: size,\r\n border: `${borderWidth}px solid ${borderColor}`,\r\n background,\r\n borderRadius: \"50%\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n pointerEvents: \"none\",\r\n zIndex: 9999,\r\n opacity: 0,\r\n transform: \"scale(0)\",\r\n fontFamily,\r\n fontSize,\r\n fontWeight,\r\n letterSpacing,\r\n textTransform: \"uppercase\",\r\n color: borderColor,\r\n }}\r\n >\r\n {text}\r\n </div>\r\n );\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/cursor/CursorFollower/CursorFollower.tsx"],"names":["useRef","useLayoutEffect","gsap","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import { useLayoutEffect, useRef } from \"react\";\r\nimport gsap from \"gsap\";\r\n\r\nexport type CursorFollowerProps = {\r\n text?: string;\r\n\r\n size?: number;\r\n borderWidth?: number;\r\n borderColor?: string;\r\n background?: string;\r\n\r\n fontFamily?: string;\r\n fontSize?: number;\r\n fontWeight?: number | string;\r\n letterSpacing?: number;\r\n\r\n lerp?: number;\r\n showScale?: number;\r\n hideScale?: number;\r\n\r\n enabled?: boolean;\r\n blockSelectors?: string[];\r\n containerRef?: React.RefObject<HTMLElement>;\r\n};\r\n\r\nexport const CursorFollower = ({\r\n text = \"PLAY\",\r\n size = 90,\r\n borderWidth = 2,\r\n borderColor = \"#ffffff\",\r\n background = \"transparent\",\r\n\r\n fontFamily = \"inherit\",\r\n fontSize = 12,\r\n fontWeight = 400,\r\n letterSpacing = 2,\r\n\r\n lerp = 0.035,\r\n showScale = 1,\r\n hideScale = 0,\r\n\r\n enabled = true,\r\n blockSelectors = [\"button\", \"a\"],\r\n containerRef,\r\n}: CursorFollowerProps) => {\r\n const cursorRef = useRef<HTMLDivElement>(null);\r\n\r\n useLayoutEffect(() => {\r\n if (!enabled) return;\r\n\r\n const cursor = cursorRef.current;\r\n if (!cursor) return;\r\n\r\n let targetX = 0;\r\n let targetY = 0;\r\n let currentX = 0;\r\n let currentY = 0;\r\n let visible = false;\r\n let blocked = false;\r\n\r\n const show = () => {\r\n if (visible || blocked) return;\r\n visible = true;\r\n gsap.to(cursor, { scale: showScale, opacity: 1, duration: 0.25 });\r\n };\r\n\r\n const hide = () => {\r\n if (!visible) return;\r\n visible = false;\r\n gsap.to(cursor, { scale: hideScale, opacity: 0, duration: 0.25 });\r\n };\r\n\r\n const move = (e: MouseEvent) => {\r\n if (containerRef?.current) {\r\n const bounds = containerRef.current.getBoundingClientRect();\r\n targetX = e.clientX - bounds.left;\r\n targetY = e.clientY - bounds.top;\r\n } else {\r\n targetX = e.clientX;\r\n targetY = e.clientY;\r\n }\r\n\r\n // Ensure cursor is visible if it moves\r\n if (!visible && !blocked) {\r\n show();\r\n }\r\n };\r\n\r\n const update = () => {\r\n currentX += (targetX - currentX) * lerp;\r\n currentY += (targetY - currentY) * lerp;\r\n\r\n gsap.set(cursor, {\r\n x: currentX - size / 2,\r\n y: currentY - size / 2,\r\n });\r\n };\r\n\r\n // Event Listeners Source\r\n const target = containerRef?.current || window;\r\n\r\n target.addEventListener(\"mousemove\", move as any);\r\n target.addEventListener(\"mouseenter\", show as any);\r\n target.addEventListener(\"mouseleave\", hide as any);\r\n\r\n gsap.ticker.add(update);\r\n\r\n // Force initial visibility and positioning\r\n requestAnimationFrame(() => {\r\n if (containerRef?.current) {\r\n const bounds = containerRef.current.getBoundingClientRect();\r\n targetX = bounds.width / 2;\r\n targetY = bounds.height / 2;\r\n } else {\r\n targetX = window.innerWidth / 2;\r\n targetY = window.innerHeight / 2;\r\n }\r\n\r\n // Set current position immediately to avoid lerp from 0,0\r\n currentX = targetX;\r\n currentY = targetY;\r\n\r\n gsap.set(cursor, {\r\n x: currentX - size / 2,\r\n y: currentY - size / 2\r\n });\r\n\r\n show();\r\n });\r\n\r\n // Handle blocked selectors\r\n const cleanupFns: (() => void)[] = [];\r\n\r\n blockSelectors.forEach((selector) => {\r\n const elements = document.querySelectorAll(selector);\r\n elements.forEach((el) => {\r\n const enter = () => {\r\n blocked = true;\r\n hide();\r\n };\r\n const leave = () => {\r\n blocked = false;\r\n show();\r\n };\r\n\r\n el.addEventListener(\"mouseenter\", enter);\r\n el.addEventListener(\"mouseleave\", leave);\r\n\r\n cleanupFns.push(() => {\r\n el.removeEventListener(\"mouseenter\", enter);\r\n el.removeEventListener(\"mouseleave\", leave);\r\n });\r\n });\r\n });\r\n\r\n return () => {\r\n target.removeEventListener(\"mousemove\", move as any);\r\n target.removeEventListener(\"mouseenter\", show as any);\r\n target.removeEventListener(\"mouseleave\", hide as any);\r\n gsap.ticker.remove(update);\r\n cleanupFns.forEach((fn) => fn());\r\n };\r\n }, [\r\n enabled,\r\n size,\r\n lerp,\r\n showScale,\r\n hideScale,\r\n // Stabilize dependency: only re-run if the joined string changes\r\n blockSelectors.join(\",\"),\r\n containerRef\r\n ]);\r\n\r\n if (!enabled) return null;\r\n\r\n return (\r\n <div\r\n ref={cursorRef}\r\n style={{\r\n position: containerRef ? \"absolute\" : \"fixed\",\r\n top: 0,\r\n left: 0,\r\n width: size,\r\n height: size,\r\n border: `${borderWidth}px solid ${borderColor}`,\r\n background,\r\n borderRadius: \"50%\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n pointerEvents: \"none\",\r\n zIndex: 9999,\r\n opacity: 0,\r\n transform: \"scale(0)\",\r\n fontFamily,\r\n fontSize,\r\n fontWeight,\r\n letterSpacing,\r\n textTransform: \"uppercase\",\r\n color: borderColor,\r\n }}\r\n >\r\n {text}\r\n </div>\r\n );\r\n};\r\n"]}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { useRef, useEffect } from 'react';
1
+ import { useRef, useLayoutEffect } from 'react';
2
2
  import gsap from 'gsap';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
@@ -7,7 +7,7 @@ var CursorFollower = ({
7
7
  text = "PLAY",
8
8
  size = 90,
9
9
  borderWidth = 2,
10
- borderColor = "#fff",
10
+ borderColor = "#ffffff",
11
11
  background = "transparent",
12
12
  fontFamily = "inherit",
13
13
  fontSize = 12,
@@ -17,11 +17,11 @@ var CursorFollower = ({
17
17
  showScale = 1,
18
18
  hideScale = 0,
19
19
  enabled = true,
20
- blockSelectors = [],
20
+ blockSelectors = ["button", "a"],
21
21
  containerRef
22
22
  }) => {
23
23
  const cursorRef = useRef(null);
24
- useEffect(() => {
24
+ useLayoutEffect(() => {
25
25
  if (!enabled) return;
26
26
  const cursor = cursorRef.current;
27
27
  if (!cursor) return;
@@ -50,6 +50,9 @@ var CursorFollower = ({
50
50
  targetX = e.clientX;
51
51
  targetY = e.clientY;
52
52
  }
53
+ if (!visible && !blocked) {
54
+ show();
55
+ }
53
56
  };
54
57
  const update = () => {
55
58
  currentX += (targetX - currentX) * lerp;
@@ -64,31 +67,49 @@ var CursorFollower = ({
64
67
  target.addEventListener("mouseenter", show);
65
68
  target.addEventListener("mouseleave", hide);
66
69
  gsap.ticker.add(update);
67
- const unbinds = blockSelectors.map((selector) => {
68
- const el = document.querySelector(selector);
69
- if (!el) return () => {
70
- };
71
- const enter = () => {
72
- blocked = true;
73
- hide();
74
- };
75
- const leave = () => {
76
- blocked = false;
77
- show();
78
- };
79
- el.addEventListener("mouseenter", enter);
80
- el.addEventListener("mouseleave", leave);
81
- return () => {
82
- el.removeEventListener("mouseenter", enter);
83
- el.removeEventListener("mouseleave", leave);
84
- };
70
+ requestAnimationFrame(() => {
71
+ if (containerRef?.current) {
72
+ const bounds = containerRef.current.getBoundingClientRect();
73
+ targetX = bounds.width / 2;
74
+ targetY = bounds.height / 2;
75
+ } else {
76
+ targetX = window.innerWidth / 2;
77
+ targetY = window.innerHeight / 2;
78
+ }
79
+ currentX = targetX;
80
+ currentY = targetY;
81
+ gsap.set(cursor, {
82
+ x: currentX - size / 2,
83
+ y: currentY - size / 2
84
+ });
85
+ show();
86
+ });
87
+ const cleanupFns = [];
88
+ blockSelectors.forEach((selector) => {
89
+ const elements = document.querySelectorAll(selector);
90
+ elements.forEach((el) => {
91
+ const enter = () => {
92
+ blocked = true;
93
+ hide();
94
+ };
95
+ const leave = () => {
96
+ blocked = false;
97
+ show();
98
+ };
99
+ el.addEventListener("mouseenter", enter);
100
+ el.addEventListener("mouseleave", leave);
101
+ cleanupFns.push(() => {
102
+ el.removeEventListener("mouseenter", enter);
103
+ el.removeEventListener("mouseleave", leave);
104
+ });
105
+ });
85
106
  });
86
107
  return () => {
87
108
  target.removeEventListener("mousemove", move);
88
109
  target.removeEventListener("mouseenter", show);
89
110
  target.removeEventListener("mouseleave", hide);
90
111
  gsap.ticker.remove(update);
91
- unbinds.forEach((u) => u());
112
+ cleanupFns.forEach((fn) => fn());
92
113
  };
93
114
  }, [
94
115
  enabled,
@@ -96,7 +117,8 @@ var CursorFollower = ({
96
117
  lerp,
97
118
  showScale,
98
119
  hideScale,
99
- blockSelectors,
120
+ // Stabilize dependency: only re-run if the joined string changes
121
+ blockSelectors.join(","),
100
122
  containerRef
101
123
  ]);
102
124
  if (!enabled) return null;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cursor/CursorFollower/CursorFollower.tsx"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { useEffect, useRef } from \"react\";\r\nimport gsap from \"gsap\";\r\n\r\nexport type CursorFollowerProps = {\r\n text?: string;\r\n\r\n size?: number;\r\n borderWidth?: number;\r\n borderColor?: string;\r\n background?: string;\r\n\r\n fontFamily?: string;\r\n fontSize?: number;\r\n fontWeight?: number | string;\r\n letterSpacing?: number;\r\n\r\n lerp?: number;\r\n showScale?: number;\r\n hideScale?: number;\r\n\r\n enabled?: boolean;\r\n blockSelectors?: string[];\r\n containerRef?: React.RefObject<HTMLElement>;\r\n};\r\n\r\nexport const CursorFollower = ({\r\n text = \"PLAY\",\r\n\r\n size = 90,\r\n borderWidth = 2,\r\n borderColor = \"#fff\",\r\n background = \"transparent\",\r\n\r\n fontFamily = \"inherit\",\r\n fontSize = 12,\r\n fontWeight = 400,\r\n letterSpacing = 2,\r\n\r\n lerp = 0.035,\r\n showScale = 1,\r\n hideScale = 0,\r\n\r\n enabled = true,\r\n blockSelectors = [],\r\n containerRef,\r\n}: CursorFollowerProps) => {\r\n const cursorRef = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n if (!enabled) return;\r\n\r\n const cursor = cursorRef.current;\r\n if (!cursor) return;\r\n\r\n let targetX = 0;\r\n let targetY = 0;\r\n let currentX = 0;\r\n let currentY = 0;\r\n let visible = false;\r\n let blocked = false;\r\n\r\n const show = () => {\r\n if (visible || blocked) return;\r\n visible = true;\r\n gsap.to(cursor, { scale: showScale, opacity: 1, duration: 0.25 });\r\n };\r\n\r\n const hide = () => {\r\n if (!visible) return;\r\n visible = false;\r\n gsap.to(cursor, { scale: hideScale, opacity: 0, duration: 0.25 });\r\n };\r\n\r\n const move = (e: MouseEvent) => {\r\n if (containerRef?.current) {\r\n const bounds = containerRef.current.getBoundingClientRect();\r\n // Calculate relative coordinates\r\n targetX = e.clientX - bounds.left;\r\n targetY = e.clientY - bounds.top;\r\n } else {\r\n targetX = e.clientX;\r\n targetY = e.clientY;\r\n }\r\n };\r\n\r\n const update = () => {\r\n currentX += (targetX - currentX) * lerp;\r\n currentY += (targetY - currentY) * lerp;\r\n\r\n gsap.set(cursor, {\r\n x: currentX - size / 2,\r\n y: currentY - size / 2,\r\n });\r\n };\r\n\r\n // Event Listeners Source\r\n const target = containerRef?.current || window;\r\n\r\n target.addEventListener(\"mousemove\", move as any);\r\n target.addEventListener(\"mouseenter\", show as any);\r\n target.addEventListener(\"mouseleave\", hide as any);\r\n\r\n gsap.ticker.add(update);\r\n\r\n const unbinds = blockSelectors.map((selector) => {\r\n const el = document.querySelector(selector);\r\n if (!el) return () => { };\r\n\r\n const enter = () => {\r\n blocked = true;\r\n hide();\r\n };\r\n const leave = () => {\r\n blocked = false;\r\n show();\r\n };\r\n\r\n el.addEventListener(\"mouseenter\", enter);\r\n el.addEventListener(\"mouseleave\", leave);\r\n\r\n return () => {\r\n el.removeEventListener(\"mouseenter\", enter);\r\n el.removeEventListener(\"mouseleave\", leave);\r\n };\r\n });\r\n\r\n return () => {\r\n target.removeEventListener(\"mousemove\", move as any);\r\n target.removeEventListener(\"mouseenter\", show as any);\r\n target.removeEventListener(\"mouseleave\", hide as any);\r\n gsap.ticker.remove(update);\r\n unbinds.forEach((u) => u());\r\n };\r\n }, [\r\n enabled,\r\n size,\r\n lerp,\r\n showScale,\r\n hideScale,\r\n blockSelectors,\r\n containerRef\r\n ]);\r\n\r\n if (!enabled) return null;\r\n\r\n return (\r\n <div\r\n ref={cursorRef}\r\n style={{\r\n position: containerRef ? \"absolute\" : \"fixed\",\r\n top: 0,\r\n left: 0,\r\n width: size,\r\n height: size,\r\n border: `${borderWidth}px solid ${borderColor}`,\r\n background,\r\n borderRadius: \"50%\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n pointerEvents: \"none\",\r\n zIndex: 9999,\r\n opacity: 0,\r\n transform: \"scale(0)\",\r\n fontFamily,\r\n fontSize,\r\n fontWeight,\r\n letterSpacing,\r\n textTransform: \"uppercase\",\r\n color: borderColor,\r\n }}\r\n >\r\n {text}\r\n </div>\r\n );\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/cursor/CursorFollower/CursorFollower.tsx"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { useLayoutEffect, useRef } from \"react\";\r\nimport gsap from \"gsap\";\r\n\r\nexport type CursorFollowerProps = {\r\n text?: string;\r\n\r\n size?: number;\r\n borderWidth?: number;\r\n borderColor?: string;\r\n background?: string;\r\n\r\n fontFamily?: string;\r\n fontSize?: number;\r\n fontWeight?: number | string;\r\n letterSpacing?: number;\r\n\r\n lerp?: number;\r\n showScale?: number;\r\n hideScale?: number;\r\n\r\n enabled?: boolean;\r\n blockSelectors?: string[];\r\n containerRef?: React.RefObject<HTMLElement>;\r\n};\r\n\r\nexport const CursorFollower = ({\r\n text = \"PLAY\",\r\n size = 90,\r\n borderWidth = 2,\r\n borderColor = \"#ffffff\",\r\n background = \"transparent\",\r\n\r\n fontFamily = \"inherit\",\r\n fontSize = 12,\r\n fontWeight = 400,\r\n letterSpacing = 2,\r\n\r\n lerp = 0.035,\r\n showScale = 1,\r\n hideScale = 0,\r\n\r\n enabled = true,\r\n blockSelectors = [\"button\", \"a\"],\r\n containerRef,\r\n}: CursorFollowerProps) => {\r\n const cursorRef = useRef<HTMLDivElement>(null);\r\n\r\n useLayoutEffect(() => {\r\n if (!enabled) return;\r\n\r\n const cursor = cursorRef.current;\r\n if (!cursor) return;\r\n\r\n let targetX = 0;\r\n let targetY = 0;\r\n let currentX = 0;\r\n let currentY = 0;\r\n let visible = false;\r\n let blocked = false;\r\n\r\n const show = () => {\r\n if (visible || blocked) return;\r\n visible = true;\r\n gsap.to(cursor, { scale: showScale, opacity: 1, duration: 0.25 });\r\n };\r\n\r\n const hide = () => {\r\n if (!visible) return;\r\n visible = false;\r\n gsap.to(cursor, { scale: hideScale, opacity: 0, duration: 0.25 });\r\n };\r\n\r\n const move = (e: MouseEvent) => {\r\n if (containerRef?.current) {\r\n const bounds = containerRef.current.getBoundingClientRect();\r\n targetX = e.clientX - bounds.left;\r\n targetY = e.clientY - bounds.top;\r\n } else {\r\n targetX = e.clientX;\r\n targetY = e.clientY;\r\n }\r\n\r\n // Ensure cursor is visible if it moves\r\n if (!visible && !blocked) {\r\n show();\r\n }\r\n };\r\n\r\n const update = () => {\r\n currentX += (targetX - currentX) * lerp;\r\n currentY += (targetY - currentY) * lerp;\r\n\r\n gsap.set(cursor, {\r\n x: currentX - size / 2,\r\n y: currentY - size / 2,\r\n });\r\n };\r\n\r\n // Event Listeners Source\r\n const target = containerRef?.current || window;\r\n\r\n target.addEventListener(\"mousemove\", move as any);\r\n target.addEventListener(\"mouseenter\", show as any);\r\n target.addEventListener(\"mouseleave\", hide as any);\r\n\r\n gsap.ticker.add(update);\r\n\r\n // Force initial visibility and positioning\r\n requestAnimationFrame(() => {\r\n if (containerRef?.current) {\r\n const bounds = containerRef.current.getBoundingClientRect();\r\n targetX = bounds.width / 2;\r\n targetY = bounds.height / 2;\r\n } else {\r\n targetX = window.innerWidth / 2;\r\n targetY = window.innerHeight / 2;\r\n }\r\n\r\n // Set current position immediately to avoid lerp from 0,0\r\n currentX = targetX;\r\n currentY = targetY;\r\n\r\n gsap.set(cursor, {\r\n x: currentX - size / 2,\r\n y: currentY - size / 2\r\n });\r\n\r\n show();\r\n });\r\n\r\n // Handle blocked selectors\r\n const cleanupFns: (() => void)[] = [];\r\n\r\n blockSelectors.forEach((selector) => {\r\n const elements = document.querySelectorAll(selector);\r\n elements.forEach((el) => {\r\n const enter = () => {\r\n blocked = true;\r\n hide();\r\n };\r\n const leave = () => {\r\n blocked = false;\r\n show();\r\n };\r\n\r\n el.addEventListener(\"mouseenter\", enter);\r\n el.addEventListener(\"mouseleave\", leave);\r\n\r\n cleanupFns.push(() => {\r\n el.removeEventListener(\"mouseenter\", enter);\r\n el.removeEventListener(\"mouseleave\", leave);\r\n });\r\n });\r\n });\r\n\r\n return () => {\r\n target.removeEventListener(\"mousemove\", move as any);\r\n target.removeEventListener(\"mouseenter\", show as any);\r\n target.removeEventListener(\"mouseleave\", hide as any);\r\n gsap.ticker.remove(update);\r\n cleanupFns.forEach((fn) => fn());\r\n };\r\n }, [\r\n enabled,\r\n size,\r\n lerp,\r\n showScale,\r\n hideScale,\r\n // Stabilize dependency: only re-run if the joined string changes\r\n blockSelectors.join(\",\"),\r\n containerRef\r\n ]);\r\n\r\n if (!enabled) return null;\r\n\r\n return (\r\n <div\r\n ref={cursorRef}\r\n style={{\r\n position: containerRef ? \"absolute\" : \"fixed\",\r\n top: 0,\r\n left: 0,\r\n width: size,\r\n height: size,\r\n border: `${borderWidth}px solid ${borderColor}`,\r\n background,\r\n borderRadius: \"50%\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n pointerEvents: \"none\",\r\n zIndex: 9999,\r\n opacity: 0,\r\n transform: \"scale(0)\",\r\n fontFamily,\r\n fontSize,\r\n fontWeight,\r\n letterSpacing,\r\n textTransform: \"uppercase\",\r\n color: borderColor,\r\n }}\r\n >\r\n {text}\r\n </div>\r\n );\r\n};\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webenza/ui",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Internal UI and animation components for Webenza",
5
5
  "private": false,
6
6
  "sideEffects": false,
@@ -40,5 +40,8 @@
40
40
  "@types/react-dom": "^19.2.3",
41
41
  "tsup": "^8.5.1",
42
42
  "typescript": "^5.9.3"
43
+ },
44
+ "dependencies": {
45
+ "@webenza/ui": "^0.0.3"
43
46
  }
44
47
  }