@stianlarsen/react-fade-effects
Version:
A collection of React components for smooth fade-in animations, starting with FadeWords. Easily add fade effects to your UI elements with customizable options.
149 lines (148 loc) • 6.36 kB
JavaScript
;
// components/FadedWords.tsx
"use client";
// components/FadedWords.tsx
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FadedWords = void 0;
const framer_motion_1 = require("framer-motion");
const react_1 = __importStar(require("react"));
const fadeEffects_module_css_1 = __importDefault(require("../css/fadeEffects.module.css"));
const FadedWords = ({ words, className, filter = true, duration = 1, staggerTime = 0.1, delay = 0.2, variant = "default", scaleSize = undefined, once = true, translateAmount = undefined, splitChar = " ", // Default to space
includeSpaces = true, }) => {
const [scope, animate] = (0, framer_motion_1.useAnimate)();
const isInViewContainer = (0, react_1.useRef)(null);
const isInView = (0, framer_motion_1.useInView)(isInViewContainer, {
once,
amount: 0.5,
});
// Adjusted splitting logic
let tokensArray;
if (Array.isArray(words)) {
// If words is an array, map it to tokens
tokensArray = words.map((word) => ({ value: word, isDelimiter: false }));
}
else {
// If words is a string, tokenize it
let delimiterRegex;
if (splitChar instanceof RegExp) {
delimiterRegex = splitChar;
}
else {
// Escape any special regex characters in splitChar
delimiterRegex = new RegExp(escapeRegex(splitChar), "g");
}
tokensArray = tokenize(words, delimiterRegex);
}
(0, react_1.useEffect)(() => {
if (!isInView || !isInViewContainer.current || !scope.current)
return;
setTimeout(() => {
animate(".singleWord", {
opacity: 1,
filter: filter ? "blur(0px)" : "none",
transform: "translateY(0) scale(1)",
}, {
duration,
delay: (0, framer_motion_1.stagger)(staggerTime),
});
}, delay * 1000); // Convert delay to milliseconds
}, [isInView, animate, delay, duration, filter, staggerTime]);
const RenderWords = () => {
const initialStyleObject = getInitialStyleObject(variant, filter, scaleSize, translateAmount);
return (react_1.default.createElement(framer_motion_1.motion.span, { ref: scope, className: `${className || ""} ${fadeEffects_module_css_1.default.textEffectWrapper}` }, tokensArray.map((token, idx) => (react_1.default.createElement(framer_motion_1.motion.span, { key: token.value + idx, className: `${fadeEffects_module_css_1.default.word} singleWord`, style: initialStyleObject },
token.value,
includeSpaces &&
!token.isDelimiter &&
idx < tokensArray.length - 1 ? (react_1.default.createElement(react_1.default.Fragment, null, "\u00A0")) : null)))));
};
return (react_1.default.createElement("div", { ref: isInViewContainer, className: fadeEffects_module_css_1.default.renderWordsWrapper },
react_1.default.createElement(RenderWords, null)));
};
exports.FadedWords = FadedWords;
const getInitialStyleObject = (variant, filter, scaleSize, translateAmount) => {
const baseStyle = {
opacity: 0,
filter: filter ? "blur(20px)" : "none",
display: "inline-block",
};
let transformValue = "";
switch (variant) {
case "up":
transformValue = `translateY(${translateAmount !== undefined ? translateAmount : 15}px)`;
break;
case "down":
transformValue = `translateY(${translateAmount !== undefined ? -translateAmount : -15}px)`;
break;
case "left":
transformValue = `translateX(${translateAmount !== undefined ? translateAmount : 15}px)`;
break;
case "right":
transformValue = `translateX(${translateAmount !== undefined ? -translateAmount : -15}px)`;
break;
default:
transformValue = "";
}
if (scaleSize !== undefined) {
transformValue += ` scale(${scaleSize})`;
}
return Object.assign(Object.assign({}, baseStyle), { transform: transformValue || undefined });
};
const tokenize = (str, delimiterRegex) => {
const tokens = [];
let lastIndex = 0;
const regex = new RegExp(delimiterRegex, "g");
let match;
while ((match = regex.exec(str)) !== null) {
if (match.index > lastIndex) {
tokens.push({
value: str.slice(lastIndex, match.index),
isDelimiter: false,
});
}
tokens.push({ value: match[0], isDelimiter: true });
lastIndex = regex.lastIndex;
}
if (lastIndex < str.length) {
tokens.push({ value: str.slice(lastIndex), isDelimiter: false });
}
return tokens;
};
const escapeRegex = (str) => {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
};