@shopify/cli-kit
Version:
A set of utilities, interfaces, and models that are common across all the platform features
56 lines • 2.07 kB
JavaScript
/* eslint-disable id-length */
import { Text, useStdout } from 'ink';
import React, { memo, useCallback, useLayoutEffect, useRef, useState } from 'react';
import gradient from 'gradient-string';
function rainbow(text, frame) {
const hue = 5 * frame;
const leftColor = { h: hue % 360, s: 0.8, v: 1 };
const rightColor = { h: (hue + 1) % 360, s: 0.8, v: 1 };
return gradient(leftColor, rightColor)(text, { interpolation: 'hsv', hsvSpin: 'long' });
}
function rotated(text, steps) {
const normalizedSteps = steps % text.length;
const start = text.slice(-normalizedSteps);
const end = text.slice(0, -normalizedSteps);
return start + end;
}
function truncated(text, maxWidth) {
return maxWidth ? text.slice(0, maxWidth) : text;
}
/**
* `TextAnimation` applies a rainbow animation to text.
*/
const TextAnimation = memo(({ text, maxWidth }) => {
const frame = useRef(0);
const [renderedFrame, setRenderedFrame] = useState(text);
const timeout = useRef();
const { stdout } = useStdout();
const [width, setWidth] = useState(maxWidth ?? Math.floor(stdout.columns * 0.66));
useLayoutEffect(() => {
const handleResize = () => {
setWidth(Math.floor(stdout.columns * 0.66));
};
stdout.on('resize', handleResize);
return () => {
stdout.off('resize', handleResize);
};
}, [stdout]);
const renderAnimation = useCallback(() => {
const newFrame = frame.current + 1;
frame.current = newFrame;
setRenderedFrame(rainbow(truncated(rotated(text, frame.current), width), frame.current));
timeout.current = setTimeout(() => {
renderAnimation();
}, 35);
}, [text, width]);
useLayoutEffect(() => {
renderAnimation();
return () => {
clearTimeout(timeout.current);
};
}, [renderAnimation]);
return React.createElement(Text, null, renderedFrame);
});
TextAnimation.displayName = 'TextAnimation';
export { TextAnimation };
//# sourceMappingURL=TextAnimation.js.map