@twistezo/react-text-scramble
Version:
React text scramble effect
224 lines (217 loc) • 6.24 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __moduleCache = /* @__PURE__ */ new WeakMap;
var __toCommonJS = (from) => {
var entry = __moduleCache.get(from), desc;
if (entry)
return entry;
entry = __defProp({}, "__esModule", { value: true });
if (from && typeof from === "object" || typeof from === "function")
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
}));
__moduleCache.set(from, entry);
return entry;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, {
get: all[name],
enumerable: true,
configurable: true,
set: (newValue) => all[name] = () => newValue
});
};
// src/index.ts
var exports_src = {};
__export(exports_src, {
default: () => TextScramble_default,
createTextScramble: () => createTextScramble,
TextScrambleAnimator: () => TextScrambleAnimator,
TextScramble: () => TextScramble_default,
SYMBOLS: () => SYMBOLS,
DEFAULT_PAUSE_TIME: () => DEFAULT_PAUSE_TIME,
DEFAULT_PAUSED: () => DEFAULT_PAUSED,
DEFAULT_NEXT_LETTER_SPEED: () => DEFAULT_NEXT_LETTER_SPEED,
DEFAULT_LETTER_SPEED: () => DEFAULT_LETTER_SPEED
});
module.exports = __toCommonJS(exports_src);
// src/TextScramble.tsx
var import_react = require("react");
// src/constants.ts
var DEFAULT_LETTER_SPEED = 5;
var DEFAULT_NEXT_LETTER_SPEED = 100;
var DEFAULT_PAUSE_TIME = 1500;
var DEFAULT_PAUSED = false;
var SYMBOLS = "!<>-_\\/[]{}—=+*^?#".split("");
// src/utils.ts
var randomItem = (array) => array[Math.floor(Math.random() * array.length)];
var nextItem = (array, currentItem) => {
const currentIndex = array.indexOf(currentItem);
const bound = array.length;
const nextIndex = (currentIndex + bound + 1) % bound;
return array[nextIndex];
};
// src/TextScrambleAnimator.ts
class TextScrambleAnimator {
bakeLetterInterval = null;
bakeTextInterval = null;
currentText;
displayedText;
element;
leftIndexes = [];
letterSpeed;
nextLetterSpeed;
paused;
pauseTime;
pauseTimeout = null;
texts;
constructor(element, options) {
this.element = element;
this.texts = options.texts;
this.letterSpeed = options.letterSpeed ?? DEFAULT_LETTER_SPEED;
this.nextLetterSpeed = options.nextLetterSpeed ?? DEFAULT_NEXT_LETTER_SPEED;
this.pauseTime = options.pauseTime ?? DEFAULT_PAUSE_TIME;
this.paused = options.paused ?? DEFAULT_PAUSED;
this.currentText = this.texts[0];
this.displayedText = this.initSymbols();
this.render();
if (!this.paused) {
this.animate();
}
}
destroy() {
this.clearAllIntervals();
}
pause() {
this.paused = true;
if (this.pauseTimeout) {
clearTimeout(this.pauseTimeout);
this.pauseTimeout = null;
}
}
play() {
this.paused = false;
this.clearAllIntervals();
this.animate();
}
reset() {
this.clearAllIntervals();
this.currentText = this.texts[0];
this.displayedText = this.initSymbols();
this.render();
this.leftIndexes = [];
if (!this.paused) {
this.animate();
}
}
setTexts(texts) {
this.texts = texts;
this.reset();
}
animate() {
this.bakeText();
}
bakeLetter() {
this.bakeLetterInterval = setInterval(() => {
if (!this.paused) {
const updatedText = [];
this.currentText.split("").forEach((char, i) => {
if (!this.leftIndexes.includes(i)) {
updatedText[i] = this.currentText[i];
return;
}
updatedText[i] = randomItem(SYMBOLS);
});
this.displayedText = updatedText;
this.render();
}
}, this.letterSpeed);
}
bakeText() {
this.leftIndexes = this.currentText.split("").map((_, i) => i);
this.bakeLetter();
this.bakeTextInterval = setInterval(() => {
if (!this.paused) {
if (this.leftIndexes.length === 0) {
this.clearAllIntervals();
this.pauseTimeout = setTimeout(() => {
this.currentText = nextItem(this.texts, this.currentText);
this.displayedText = this.initSymbols();
this.render();
this.animate();
}, this.pauseTime);
return;
}
this.leftIndexes.shift();
}
}, this.nextLetterSpeed);
}
clearAllIntervals() {
if (this.bakeLetterInterval) {
clearInterval(this.bakeLetterInterval);
this.bakeLetterInterval = null;
}
if (this.bakeTextInterval) {
clearInterval(this.bakeTextInterval);
this.bakeTextInterval = null;
}
if (this.pauseTimeout) {
clearTimeout(this.pauseTimeout);
this.pauseTimeout = null;
}
}
initSymbols() {
return Array(this.currentText.length).fill(0).map(() => randomItem(SYMBOLS));
}
render() {
this.element.textContent = this.displayedText.join("");
}
}
function createTextScramble(element, options) {
return new TextScrambleAnimator(element, options);
}
// src/TextScramble.tsx
var jsx_dev_runtime = require("react/jsx-dev-runtime");
var TextScramble = ({
className,
letterSpeed,
nextLetterSpeed,
paused,
pauseTime,
texts
}) => {
const elementRef = import_react.useRef(null);
const animatorRef = import_react.useRef(null);
import_react.useEffect(() => {
if (!elementRef.current)
return;
animatorRef.current = new TextScrambleAnimator(elementRef.current, {
letterSpeed,
nextLetterSpeed,
paused,
pauseTime,
texts
});
return () => {
animatorRef.current?.destroy();
};
}, [texts, letterSpeed, nextLetterSpeed, pauseTime]);
import_react.useEffect(() => {
if (!animatorRef.current)
return;
if (paused) {
animatorRef.current.pause();
} else {
animatorRef.current.play();
}
}, [paused]);
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV("div", {
className,
ref: elementRef
}, undefined, false, undefined, this);
};
var TextScramble_default = TextScramble;