Skip to content

Commit 6d1fe9d

Browse files
committed
first commit
0 parents  commit 6d1fe9d

File tree

7 files changed

+166
-0
lines changed

7 files changed

+166
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/.vscode

README.md

Whitespace-only changes.

package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "react-twinkle-text",
3+
"version": "1.0.0",
4+
"description": "React twinkle text effect using Tailwind-compatible styles.",
5+
"main": "src/index.js",
6+
"files": ["src"],
7+
"keywords": ["react", "tailwind", "twinkle", "text", "component"],
8+
"author": "itznao",
9+
"license": "MIT",
10+
"peerDependencies": {
11+
"react": "^17.0.0 || ^18.0.0"
12+
},
13+
"repository": {
14+
"type": "git",
15+
"url": "https://github.com/itznao/react-twinkle-text"
16+
},
17+
"bugs": {
18+
"url": "https://github.com/itznao/react-twinkle-text/issues"
19+
},
20+
"homepage": "https://github.com/itznao/react-twinkle-text#readme"
21+
}

src/TwinkleText.jsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React, { useEffect } from "react";
2+
import { twinkleCSS } from "./twinkleStyles";
3+
4+
let cssInjected = false;
5+
6+
export const twinkleText = ({
7+
children,
8+
className = "",
9+
hover = false,
10+
groupHover = false,
11+
}) => {
12+
useEffect(() => {
13+
if (!cssInjected) {
14+
const style = document.createElement("style");
15+
style.textContent = twinkleCSS;
16+
document.head.appendChild(style);
17+
cssInjected = true;
18+
}
19+
}, []);
20+
21+
const twinkleClass = groupHover
22+
? "group-hover-text-twinkle"
23+
: hover
24+
? "hover-text-twinkle"
25+
: "text-twinkle";
26+
27+
return (
28+
<span text-twinkle-data={children} className={`${twinkleClass} ${className}`}>
29+
{children}
30+
</span>
31+
);
32+
};

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { TwinkleText } from "./TwinkleText";

src/twinkleStyles.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
export const twinkleCSS = `
2+
@keyframes text-twinkle {
3+
0% { background-position: 150% 0; }
4+
100% { background-position: -250% 0; }
5+
}
6+
7+
.text-twinkle,
8+
.hover-text-twinkle,
9+
.group-hover-text-twinkle {
10+
position: relative;
11+
display: inline-block;
12+
}
13+
14+
.text-twinkle::before,
15+
.hover-text-twinkle::before,
16+
.group-hover-text-twinkle::before {
17+
content: attr(text-twinkle-data);
18+
position: absolute;
19+
inset: 0;
20+
pointer-events: none;
21+
color: transparent;
22+
background-clip: text;
23+
background-image: linear-gradient(
24+
90deg,
25+
transparent,
26+
transparent,
27+
white,
28+
transparent,
29+
transparent
30+
);
31+
background-size: 200% 100%;
32+
background-position: 150% 0;
33+
filter: drop-shadow(0 0 1px #ffffff)
34+
drop-shadow(0 0 2px rgba(255, 255, 255, 0.5));
35+
}
36+
37+
.text-twinkle::before {
38+
animation: text-twinkle 5s linear infinite;
39+
}
40+
41+
.hover-text-twinkle::before,
42+
.group-hover-text-twinkle::before {
43+
opacity: 0;
44+
}
45+
46+
.hover-text-twinkle:hover::before,
47+
.group:hover .group-hover-text-twinkle::before {
48+
opacity: 1;
49+
animation: text-twinkle 5s linear infinite;
50+
}
51+
`;

tailwind-plugin.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const plugin = require("tailwindcss/plugin");
2+
3+
module.exports = plugin(function ({ addUtilities, addComponents }) {
4+
addUtilities({
5+
'@keyframes text-shimmer': {
6+
'0%': { 'background-position': '150% 0' },
7+
'100%': { 'background-position': '-250% 0' },
8+
},
9+
});
10+
11+
const shimmerBefore = {
12+
content: 'attr(text-shimmer-data)',
13+
position: 'absolute',
14+
inset: '0',
15+
'pointer-events': 'none',
16+
color: 'transparent',
17+
'background-clip': 'text',
18+
'background-image':
19+
'linear-gradient(90deg, #0000, #0000, #0000, #fff, #0000, #0000, #0000)',
20+
'background-size': '200% 100%',
21+
'background-position': '150% 0',
22+
filter:
23+
'drop-shadow(0 0 1px #ffffff) drop-shadow(0 0 2px rgba(255,255,255,0.5))',
24+
};
25+
26+
addComponents({
27+
'.text-shimmer': {
28+
position: 'relative',
29+
display: 'inline-block',
30+
},
31+
'.text-shimmer::before': {
32+
...shimmerBefore,
33+
animation: 'text-shimmer 5s linear infinite',
34+
},
35+
'.hover-text-shimmer': {
36+
position: 'relative',
37+
display: 'inline-block',
38+
},
39+
'.hover-text-shimmer::before': {
40+
...shimmerBefore,
41+
opacity: '0',
42+
},
43+
'.hover-text-shimmer:hover::before': {
44+
animation: 'text-shimmer 5s linear infinite',
45+
opacity: '1',
46+
},
47+
'.group-hover-text-shimmer': {
48+
position: 'relative',
49+
display: 'inline-block',
50+
},
51+
'.group-hover-text-shimmer::before': {
52+
...shimmerBefore,
53+
opacity: '0',
54+
},
55+
'.group:hover .group-hover-text-shimmer::before': {
56+
animation: 'text-shimmer 5s linear infinite',
57+
opacity: '1',
58+
},
59+
});
60+
});

0 commit comments

Comments
 (0)