ink-motion 1.0.0 â 1.0.2
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/README.md +1 -2
- package/dist/index.cjs +24 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -20
- package/dist/index.d.ts +19 -20
- package/dist/index.js +24 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Beautiful, performant text effects and animations for [Ink](https://github.com/v
|
|
|
6
6
|
|
|
7
7
|
- ðĻ **Rich text effects**: Shimmer, Typewriter, Fade, Wave, Flash
|
|
8
8
|
- ⥠**Performant**: Optimised animations with minimal re-renders
|
|
9
|
-
- ð§ **Highly customisable**: Control
|
|
9
|
+
- ð§ **Highly customisable**: Control colors, speed, intensity, and more
|
|
10
10
|
- ðĶ **Type-safe**: Full TypeScript support with strict types
|
|
11
11
|
- ðŠķ **Lightweight**: Minimal dependencies
|
|
12
12
|
|
|
@@ -23,7 +23,6 @@ pnpm add ink-motion
|
|
|
23
23
|
```tsx
|
|
24
24
|
import { render } from 'ink'
|
|
25
25
|
import { Shimmer, Typewriter } from 'ink-motion'
|
|
26
|
-
import React from 'react'
|
|
27
26
|
|
|
28
27
|
function App() {
|
|
29
28
|
return (
|
package/dist/index.cjs
CHANGED
|
@@ -70,6 +70,8 @@ function hexToRgb(hex) {
|
|
|
70
70
|
if (!result)
|
|
71
71
|
return null;
|
|
72
72
|
const [, redHex, greenHex, blueHex] = result;
|
|
73
|
+
if (!redHex || !greenHex || !blueHex)
|
|
74
|
+
return null;
|
|
73
75
|
return [
|
|
74
76
|
Number.parseInt(redHex, HEX_BASE),
|
|
75
77
|
Number.parseInt(greenHex, HEX_BASE),
|
|
@@ -85,6 +87,8 @@ function colorize(text, color) {
|
|
|
85
87
|
if (!match || match.length < MIN_RGB_COMPONENTS)
|
|
86
88
|
return text;
|
|
87
89
|
const [redStr, greenStr, blueStr] = match;
|
|
90
|
+
if (!redStr || !greenStr || !blueStr)
|
|
91
|
+
return text;
|
|
88
92
|
const red = Number.parseInt(redStr, DECIMAL_BASE);
|
|
89
93
|
const green = Number.parseInt(greenStr, DECIMAL_BASE);
|
|
90
94
|
const blue = Number.parseInt(blueStr, DECIMAL_BASE);
|
|
@@ -136,11 +140,17 @@ var easeOut = (time) => time * (2 - time);
|
|
|
136
140
|
var easeInOut = (time) => {
|
|
137
141
|
return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time;
|
|
138
142
|
};
|
|
143
|
+
var sineIn = (time) => 1 - Math.cos(time * Math.PI / 2);
|
|
144
|
+
var sineOut = (time) => Math.sin(time * Math.PI / 2);
|
|
145
|
+
var sineInOut = (time) => -(Math.cos(Math.PI * time) - 1) / 2;
|
|
139
146
|
var easingFunctions = {
|
|
140
147
|
"linear": linear,
|
|
141
148
|
"ease-in": easeIn,
|
|
142
149
|
"ease-out": easeOut,
|
|
143
|
-
"ease-in-out": easeInOut
|
|
150
|
+
"ease-in-out": easeInOut,
|
|
151
|
+
"sine-in": sineIn,
|
|
152
|
+
"sine-out": sineOut,
|
|
153
|
+
"sine-in-out": sineInOut
|
|
144
154
|
};
|
|
145
155
|
function getEasingFunction(name = "linear") {
|
|
146
156
|
return easingFunctions[name];
|
|
@@ -151,7 +161,7 @@ function clamp(value, min, max) {
|
|
|
151
161
|
var DEFAULT_FROM = 0;
|
|
152
162
|
var DEFAULT_TO = 1;
|
|
153
163
|
var DEFAULT_DURATION_MS = 1e3;
|
|
154
|
-
var DEFAULT_EASING = "
|
|
164
|
+
var DEFAULT_EASING = "sine-in-out";
|
|
155
165
|
var DEFAULT_LOOP = false;
|
|
156
166
|
var DEFAULT_SPEED = 1;
|
|
157
167
|
function calculateOpacity(elapsedTime, duration, from, to, easing) {
|
|
@@ -183,10 +193,20 @@ function Fade({
|
|
|
183
193
|
}
|
|
184
194
|
}, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete]);
|
|
185
195
|
const fadedText = react.useMemo(() => {
|
|
186
|
-
|
|
196
|
+
let effectiveTime = elapsedTime;
|
|
197
|
+
if (loop) {
|
|
198
|
+
const cycleTime = elapsedTime % (duration * 2);
|
|
199
|
+
effectiveTime = cycleTime > duration ? duration * 2 - cycleTime : cycleTime;
|
|
200
|
+
} else {
|
|
201
|
+
effectiveTime = Math.min(elapsedTime, duration);
|
|
202
|
+
}
|
|
187
203
|
const opacity = calculateOpacity(effectiveTime, duration, from, to, easing);
|
|
204
|
+
if (opacity < 0.01) {
|
|
205
|
+
return "";
|
|
206
|
+
}
|
|
188
207
|
const baseColor = color ?? "#ffffff";
|
|
189
|
-
const
|
|
208
|
+
const elegantOpacity = opacity ** 1.5;
|
|
209
|
+
const fadedColor = interpolateColor("#000000", baseColor, elegantOpacity);
|
|
190
210
|
return colorize(children, fadedColor);
|
|
191
211
|
}, [children, elapsedTime, duration, from, to, easing, color, loop]);
|
|
192
212
|
return /* @__PURE__ */ jsxRuntime.jsx(ink.Text, { children: fadedText });
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useAnimationFrame.ts","../src/hooks/useElapsedTime.ts","../src/utils/colors.ts","../src/utils/easing.ts","../src/components/Fade.tsx","../src/components/Flash.tsx","../src/utils/text.ts","../src/components/Shimmer.tsx","../src/hooks/useCursorBlink.ts","../src/hooks/useTypewriterProgress.ts","../src/components/Typewriter.tsx","../src/components/Wave.tsx"],"names":["useRef","useEffect","useState","chalk","useMemo","jsx","Text","DEFAULT_DURATION_MS","DEFAULT_SPEED","MIN_INTENSITY","MAX_INTENSITY","FIRST_CHARACTER_INDEX","DEFAULT_COLORS","FULL_CIRCLE_RADIANS","SINE_WAVE_OFFSET","SINE_WAVE_NORMALIZE"],"mappings":"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","file":"index.cjs","sourcesContent":["import { useEffect, useRef } from 'react'\n\nconst TARGET_FPS = 60\nconst FRAME_INTERVAL_MS = 1000 / TARGET_FPS\n\n/**\n * Runs a callback on every animation frame using setInterval\n *\n * @param callback - Function called each frame with delta time in ms\n * @param enabled - Whether animation is active\n */\nexport function useAnimationFrame(\n callback: (deltaTime: number) => void,\n enabled: boolean = true,\n): void {\n const intervalRef = useRef<Timer>()\n const previousTimeRef = useRef<number>()\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n previousTimeRef.current = undefined\n return\n }\n\n intervalRef.current = setInterval(() => {\n const currentTime = Date.now()\n if (previousTimeRef.current !== undefined) {\n const deltaTime = currentTime - previousTimeRef.current\n callbackRef.current(deltaTime)\n }\n previousTimeRef.current = currentTime\n }, FRAME_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [enabled])\n}\n","import { useState } from 'react'\nimport { useAnimationFrame } from './useAnimationFrame.js'\n\n/**\n * Hook that tracks elapsed time since mount or last reset\n *\n * @param enabled - Whether to track time\n * @param speed - Speed multiplier (default: 1)\n * @returns Elapsed time in milliseconds\n */\nexport function useElapsedTime(\n enabled: boolean = true,\n speed: number = 1,\n): number {\n const [elapsedTime, setElapsedTime] = useState(0)\n\n useAnimationFrame((deltaTime) => {\n setElapsedTime(prev => prev + deltaTime * speed)\n }, enabled)\n\n return elapsedTime\n}\n","import type { Colour } from '../types/index.js'\nimport chalk from 'chalk'\n\nconst HEX_BASE = 16\nconst DECIMAL_BASE = 10\nconst HEX_BYTE_LENGTH = 2\nconst HEX_PAD_CHARACTER = '0'\nconst MIN_RGB_COMPONENTS = 3\nconst INTERPOLATION_MIDPOINT = 0.5\n\nconst HEX_COLOR_REGEX = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i\nconst RGB_NUMBERS_REGEX = /\\d+/g\n\nfunction rgbToHex(red: number, green: number, blue: number): string {\n const redHex = red.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const greenHex = green.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const blueHex = blue.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n return `#${redHex}${greenHex}${blueHex}`\n}\n\n/**\n * Converts a hex color string to RGB values\n *\n * @param hex - Hex color string (with or without #)\n * @returns Tuple of [red, green, blue] values (0-255) or null if invalid\n */\nexport function hexToRgb(hex: string): [number, number, number] | null {\n const result = HEX_COLOR_REGEX.exec(hex)\n if (!result)\n return null\n\n const [, redHex, greenHex, blueHex] = result\n return [\n Number.parseInt(redHex, HEX_BASE),\n Number.parseInt(greenHex, HEX_BASE),\n Number.parseInt(blueHex, HEX_BASE),\n ]\n}\n\n/**\n * Applies color to text using chalk\n *\n * @param text - Text to colorize\n * @param color - Color as hex (#ff0000), rgb(255,0,0), or named color (red, blue, etc)\n * @returns Colorized text with ANSI escape codes\n */\nexport function colorize(text: string, color: Colour): string {\n try {\n if (color.startsWith('#'))\n return chalk.hex(color)(text)\n\n if (color.startsWith('rgb')) {\n const match = color.match(RGB_NUMBERS_REGEX)\n if (!match || match.length < MIN_RGB_COMPONENTS)\n return text\n\n const [redStr, greenStr, blueStr] = match\n const red = Number.parseInt(redStr, DECIMAL_BASE)\n const green = Number.parseInt(greenStr, DECIMAL_BASE)\n const blue = Number.parseInt(blueStr, DECIMAL_BASE)\n\n if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue))\n return text\n\n return chalk.rgb(red, green, blue)(text)\n }\n\n const chalkColor = chalk[color as keyof typeof chalk]\n if (typeof chalkColor === 'function')\n return chalkColor(text)\n\n return text\n }\n catch {\n return text\n }\n}\n\n/**\n * Applies opacity to a hex color by darkening it\n * Note: Terminal approximation - true opacity not possible in most terminals\n *\n * @param color - Hex color string\n * @param opacity - Opacity value from 0 (transparent/black) to 1 (fully opaque)\n * @returns Adjusted hex color or original color if not hex format\n */\nexport function applyOpacity(color: Colour, opacity: number): Colour {\n if (!color.startsWith('#'))\n return color\n\n const rgb = hexToRgb(color)\n if (!rgb)\n return color\n\n const [red, green, blue] = rgb\n const adjustedRed = Math.round(red * opacity)\n const adjustedGreen = Math.round(green * opacity)\n const adjustedBlue = Math.round(blue * opacity)\n\n return rgbToHex(adjustedRed, adjustedGreen, adjustedBlue)\n}\n\n/**\n * Interpolates between two colors\n *\n * @param color1 - Starting color\n * @param color2 - Ending color\n * @param progress - Interpolation progress from 0 to 1\n * @returns Interpolated color (hex if both inputs are hex, otherwise snaps to nearest)\n */\nexport function interpolateColor(\n color1: Colour,\n color2: Colour,\n progress: number,\n): Colour {\n const isColor1Hex = color1.startsWith('#')\n const isColor2Hex = color2.startsWith('#')\n\n if (!isColor1Hex || !isColor2Hex)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const rgb1 = hexToRgb(color1)\n const rgb2 = hexToRgb(color2)\n\n if (!rgb1 || !rgb2)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const [red1, green1, blue1] = rgb1\n const [red2, green2, blue2] = rgb2\n\n const red = Math.round(red1 + (red2 - red1) * progress)\n const green = Math.round(green1 + (green2 - green1) * progress)\n const blue = Math.round(blue1 + (blue2 - blue1) * progress)\n\n return rgbToHex(red, green, blue)\n}\n","import type { EasingFunction, EasingName } from '../types/index.js'\n\nexport const linear: EasingFunction = time => time\n\nexport const easeIn: EasingFunction = time => time * time\n\nexport const easeOut: EasingFunction = time => time * (2 - time)\n\nexport const easeInOut: EasingFunction = (time) => {\n return time < 0.5\n ? 2 * time * time\n : -1 + (4 - 2 * time) * time\n}\n\nexport const easingFunctions: Record<EasingName, EasingFunction> = {\n 'linear': linear,\n 'ease-in': easeIn,\n 'ease-out': easeOut,\n 'ease-in-out': easeInOut,\n}\n\nexport function getEasingFunction(name: EasingName = 'linear'): EasingFunction {\n return easingFunctions[name]\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n return clamp((value - min) / (max - min), 0, 1)\n}\n\nexport function lerp(start: number, end: number, progress: number): number {\n return start + (end - start) * progress\n}\n","import type { BaseEffectProps, Colour, EasingName } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { getEasingFunction } from '../utils/easing.js'\n\ninterface FadeProps extends BaseEffectProps {\n /**\n * Text colour\n * @default '#ffffff'\n * @example 'yellow'\n */\n color?: Colour\n\n /**\n * Starting opacity (0-1)\n * @default 0\n */\n from?: number\n\n /**\n * Ending opacity (0-1)\n * @default 1\n */\n to?: number\n\n /**\n * Duration in milliseconds\n * @default 1000\n */\n duration?: number\n\n /**\n * Easing function\n * @default 'ease-out'\n */\n easing?: EasingName\n\n /**\n * Loop animation continuously\n * @default false\n */\n loop?: boolean\n}\n\nconst DEFAULT_FROM = 0\nconst DEFAULT_TO = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_EASING: EasingName = 'ease-out'\nconst DEFAULT_LOOP = false\nconst DEFAULT_SPEED = 1\n\nfunction calculateOpacity(\n elapsedTime: number,\n duration: number,\n from: number,\n to: number,\n easing: EasingName,\n): number {\n const progress = Math.min(elapsedTime / duration, 1)\n const easedProgress = getEasingFunction(easing)(progress)\n return from + (to - from) * easedProgress\n}\n\n/**\n * Fade effect component that smoothly transitions text opacity\n *\n * Animates text from one opacity to another using configurable easing functions.\n * Can loop continuously or run once.\n *\n * @example\n * ```tsx\n * <Fade color=\"yellow\" from={0} to={1} duration={500} easing=\"ease-in\">\n * Success!\n * </Fade>\n * ```\n */\nexport function Fade({\n children,\n color,\n from = DEFAULT_FROM,\n to = DEFAULT_TO,\n duration = DEFAULT_DURATION_MS,\n easing = DEFAULT_EASING,\n loop = DEFAULT_LOOP,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: FadeProps) {\n const [hasCompleted, setHasCompleted] = useState(false)\n const elapsedTime = useElapsedTime(enabled && !hasCompleted, speed)\n\n useEffect(() => {\n if (!enabled)\n return\n\n const isComplete = elapsedTime >= duration\n\n if (isComplete && !loop && !hasCompleted) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: prevents calling onComplete multiple times by setting completion flag once\n setHasCompleted(true)\n onComplete?.()\n }\n }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete])\n\n const fadedText = useMemo(() => {\n const effectiveTime = loop ? elapsedTime % duration : Math.min(elapsedTime, duration)\n const opacity = calculateOpacity(effectiveTime, duration, from, to, easing)\n\n const baseColor = color ?? '#ffffff'\n const fadedColor = applyOpacity(baseColor, opacity)\n\n return colorize(children, fadedColor)\n }, [children, elapsedTime, duration, from, to, easing, color, loop])\n\n return <Text>{fadedText}</Text>\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\n\ninterface FlashProps extends BaseEffectProps {\n /**\n * Text colour\n * @default '#ffffff'\n * @example 'cyan'\n */\n color?: Colour\n\n /**\n * Minimum brightness (0-1)\n * @default 0.3\n */\n minIntensity?: number\n\n /**\n * Maximum brightness (0-1)\n * @default 1\n */\n maxIntensity?: number\n\n /**\n * Flash cycle duration in milliseconds\n * @default 1000\n */\n duration?: number\n}\n\nconst DEFAULT_COLOR = '#ffffff'\nconst DEFAULT_MIN_INTENSITY = 0.3\nconst DEFAULT_MAX_INTENSITY = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\nfunction calculateFlashIntensity(\n time: number,\n duration: number,\n minIntensity: number,\n maxIntensity: number,\n): number {\n const clampedMin = clamp(minIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const clampedMax = clamp(maxIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const normalizedTime = time / duration\n const phase = normalizedTime * FULL_CIRCLE_RADIANS\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const intensityRange = clampedMax - clampedMin\n return clampedMin + normalizedSine * intensityRange\n}\n\n/**\n * Flash effect component that creates a pulsing neon-like glow\n *\n * Animates text with a continuous brightness pulse that oscillates\n * between minimum and maximum intensity levels, creating a flashing\n * or glowing neon effect.\n *\n * @example\n * ```tsx\n * <Flash color=\"cyan\" minIntensity={0.3} maxIntensity={1} duration={800}>\n * ⥠NEON GLOW âĄ\n * </Flash>\n * ```\n */\nexport function Flash({\n children,\n color = DEFAULT_COLOR,\n minIntensity = DEFAULT_MIN_INTENSITY,\n maxIntensity = DEFAULT_MAX_INTENSITY,\n duration = DEFAULT_DURATION_MS,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: FlashProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const cycleTime = elapsedTime % duration\n\n const flashText = useMemo(() => {\n const intensity = calculateFlashIntensity(cycleTime, duration, minIntensity, maxIntensity)\n const adjustedColor = applyOpacity(color, intensity)\n return colorize(children, adjustedColor)\n }, [children, cycleTime, duration, minIntensity, maxIntensity, color])\n\n return <Text>{flashText}</Text>\n}\n","export function splitChars(text: string): string[] {\n return [...text]\n}\n\nexport function getTextLength(text: string): number {\n return [...text].length\n}\n\nexport function mapChars(\n text: string,\n fn: (char: string, index: number) => string,\n): string {\n return splitChars(text).map(fn).join('')\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo, useState } from 'react'\nimport { useAnimationFrame } from '../hooks/useAnimationFrame.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { getTextLength, mapChars } from '../utils/text.js'\n\ntype ShimmerDirection = 'left' | 'right'\n\ninterface ShimmerProps extends BaseEffectProps {\n /**\n * Gradient colours for the shimmer effect [start, peak, end]\n * @default ['#666666', '#ffffff', '#666666']\n * @example ['#60a5fa', '#3b82f6', '#60a5fa']\n */\n colors?: [Colour, Colour, Colour]\n\n /**\n * Width of the shimmer band in characters\n * @default 4\n */\n width?: number\n\n /**\n * Brightness multiplier (0-1)\n * @default 1\n */\n intensity?: number\n\n /**\n * Direction of shimmer movement\n * @default 'right'\n */\n direction?: ShimmerDirection\n}\n\nconst DEFAULT_COLORS: [Colour, Colour, Colour] = ['#666666', '#ffffff', '#666666']\nconst DEFAULT_WIDTH = 4\nconst DEFAULT_INTENSITY = 1\nconst DEFAULT_DIRECTION: ShimmerDirection = 'right'\nconst DEFAULT_SPEED = 1\nconst ANIMATION_CYCLE_MS = 2000\nconst COLOUR_TRANSITION_MIDPOINT = 0.5\nconst COLOUR_PROGRESS_MULTIPLIER = 2\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\n/**\n * Shimmer effect component that creates a moving highlight across text\n *\n * Creates a shimmering animation by interpolating through a gradient of colours\n * that sweeps across the text from left to right or right to left.\n *\n * @example\n * ```tsx\n * <Shimmer colors={['#60a5fa', '#3b82f6', '#60a5fa']} intensity={0.8}>\n * Loading...\n * </Shimmer>\n * ```\n */\nexport function Shimmer({\n children,\n colors = DEFAULT_COLORS,\n width = DEFAULT_WIDTH,\n intensity = DEFAULT_INTENSITY,\n direction = DEFAULT_DIRECTION,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: ShimmerProps) {\n const [offset, setOffset] = useState(0)\n const textLength = getTextLength(children)\n const totalWidth = textLength + width\n\n useAnimationFrame((deltaTime) => {\n setOffset((previousOffset) => {\n const movement = (deltaTime / ANIMATION_CYCLE_MS) * speed * totalWidth\n const newOffset = direction === 'right'\n ? previousOffset + movement\n : previousOffset - movement\n\n const hasCompletedCycle = Math.abs(newOffset) >= totalWidth\n if (hasCompletedCycle) {\n onComplete?.()\n return 0\n }\n\n return newOffset\n })\n }, enabled)\n\n const shimmerText = useMemo(() => {\n return mapChars(children, (char, index) => {\n const normalizedOffset = direction === 'right' ? offset : totalWidth - offset\n const distance = Math.abs(index - normalizedOffset)\n\n const isWithinShimmerWidth = distance < width\n const colorProgress = isWithinShimmerWidth\n ? distance / width\n : 1\n\n const [startColor, peakColor, endColor] = colors\n const adjustedIntensity = clamp(intensity, MIN_INTENSITY, MAX_INTENSITY)\n\n const isFirstHalf = colorProgress < COLOUR_TRANSITION_MIDPOINT\n const currentColor = isFirstHalf\n ? interpolateColor(\n startColor,\n peakColor,\n colorProgress * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n : interpolateColor(\n peakColor,\n endColor,\n (colorProgress - COLOUR_TRANSITION_MIDPOINT) * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n\n return colorize(char, currentColor)\n })\n }, [children, offset, colors, width, intensity, direction, totalWidth])\n\n return <Text>{shimmerText}</Text>\n}\n","import { useEffect, useRef, useState } from 'react'\n\nconst CURSOR_BLINK_INTERVAL_MS = 500\n\ninterface UseCursorBlinkOptions {\n enabled: boolean\n isComplete: boolean\n}\n\n/**\n * Hook that manages cursor blinking state\n *\n * @param options - Configuration for cursor blink\n * @param options.enabled - Whether cursor blinking is enabled\n * @param options.isComplete - Whether typing is complete\n * @returns Whether cursor should be visible\n */\nexport function useCursorBlink({\n enabled,\n isComplete,\n}: UseCursorBlinkOptions): boolean {\n const [showCursor, setShowCursor] = useState(true)\n const intervalRef = useRef<Timer>()\n\n useEffect(() => {\n if (!enabled || isComplete) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: synchronizing cursor visibility with prop changes\n setShowCursor(false)\n return\n }\n\n intervalRef.current = setInterval(() => {\n setShowCursor(previous => !previous)\n }, CURSOR_BLINK_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current)\n clearInterval(intervalRef.current)\n }\n }, [enabled, isComplete])\n\n return showCursor\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { clamp } from '../utils/easing.js'\n\nconst BASE_CHARACTER_DELAY_MS = 80\nconst MIN_VARIANCE = 0\nconst MAX_VARIANCE = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction calculateCharacterDelay(\n speed: number,\n variance: number,\n): number {\n const clampedVariance = clamp(variance, MIN_VARIANCE, MAX_VARIANCE)\n const randomVariance = (Math.random() - 0.5) * clampedVariance\n return (BASE_CHARACTER_DELAY_MS / speed) * (1 + randomVariance)\n}\n\ninterface UseTypewriterProgressOptions {\n totalCharacters: number\n speed: number\n variance: number\n initialDelay: number\n enabled: boolean\n onComplete?: () => void\n}\n\n/**\n * Hook that manages typewriter character reveal timing\n *\n * @param options - Configuration for typewriter progress\n * @param options.totalCharacters - Total number of characters to reveal\n * @param options.speed - Animation speed multiplier\n * @param options.variance - Typing variance for human-like timing (0-1)\n * @param options.initialDelay - Delay before typing starts in milliseconds\n * @param options.enabled - Whether the animation is enabled\n * @param options.onComplete - Callback when typing completes\n * @returns Number of characters to display\n */\nexport function useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay,\n enabled,\n onComplete,\n}: UseTypewriterProgressOptions): number {\n const [visibleCharacters, setVisibleCharacters] = useState(0)\n const timeoutRef = useRef<Timer>()\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n\n useEffect(() => {\n if (!enabled)\n return\n\n if (hasCompletedTyping) {\n onComplete?.()\n return\n }\n\n const characterDelay = calculateCharacterDelay(speed, variance)\n const isFirstCharacter = visibleCharacters === FIRST_CHARACTER_INDEX\n const totalDelay = isFirstCharacter ? initialDelay + characterDelay : characterDelay\n\n timeoutRef.current = setTimeout(() => {\n setVisibleCharacters(previous => previous + 1)\n }, totalDelay)\n\n return () => {\n if (timeoutRef.current)\n clearTimeout(timeoutRef.current)\n }\n }, [visibleCharacters, enabled, speed, variance, initialDelay, hasCompletedTyping, onComplete])\n\n return visibleCharacters\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useCursorBlink } from '../hooks/useCursorBlink.js'\nimport { useTypewriterProgress } from '../hooks/useTypewriterProgress.js'\nimport { colorize } from '../utils/colors.js'\nimport { getTextLength, splitChars } from '../utils/text.js'\n\ninterface TypewriterProps extends BaseEffectProps {\n /**\n * Text colour\n * @default undefined (inherits)\n * @example 'green'\n */\n color?: Colour\n\n /**\n * Cursor character or false to disable\n * @default 'â'\n * @example 'â'\n */\n cursor?: string | boolean\n\n /**\n * Cursor colour (defaults to text colour)\n * @default undefined\n * @example 'cyan'\n */\n cursorColor?: Colour\n\n /**\n * Typing speed randomness (0-1) for more human-like typing\n * @default 0.3\n */\n variance?: number\n\n /**\n * Initial delay before typing starts (ms)\n * @default 0\n */\n delay?: number\n}\n\nconst DEFAULT_CURSOR = 'â'\nconst DEFAULT_VARIANCE = 0.3\nconst DEFAULT_DELAY = 0\nconst DEFAULT_SPEED = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction getCursorCharacter(cursor: string | boolean): string {\n return typeof cursor === 'string' ? cursor : DEFAULT_CURSOR\n}\n\nfunction formatCursor(\n cursorCharacter: string,\n cursorColor: Colour | undefined,\n textColor: Colour | undefined,\n): string {\n if (cursorColor)\n return colorize(cursorCharacter, cursorColor)\n\n if (textColor)\n return colorize(cursorCharacter, textColor)\n\n return cursorCharacter\n}\n\n/**\n * Typewriter effect component that reveals text character by character\n *\n * Simulates typing text with configurable speed, variance for realistic timing,\n * and an optional cursor. The cursor blinks while typing is in progress.\n *\n * @example\n * ```tsx\n * <Typewriter color=\"green\" cursor=\"â\" variance={0.5} speed={2}>\n * npm install ink-motion\n * </Typewriter>\n * ```\n */\nexport function Typewriter({\n children,\n color,\n cursor = DEFAULT_CURSOR,\n cursorColor,\n variance = DEFAULT_VARIANCE,\n delay = DEFAULT_DELAY,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: TypewriterProps) {\n const characters = splitChars(children)\n const totalCharacters = getTextLength(children)\n\n const visibleCharacters = useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay: delay,\n enabled,\n onComplete,\n })\n\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n const isCursorEnabled = cursor !== false\n\n const showCursor = useCursorBlink({\n enabled: enabled && isCursorEnabled,\n isComplete: hasCompletedTyping,\n })\n\n const displayText = useMemo(() => {\n const visibleText = characters.slice(FIRST_CHARACTER_INDEX, visibleCharacters).join('')\n const coloredText = color ? colorize(visibleText, color) : visibleText\n\n const shouldShowCursor = isCursorEnabled && showCursor && !hasCompletedTyping\n if (!shouldShowCursor)\n return coloredText\n\n const cursorCharacter = getCursorCharacter(cursor)\n const cursorText = formatCursor(cursorCharacter, cursorColor, color)\n\n return coloredText + cursorText\n }, [characters, visibleCharacters, color, cursor, cursorColor, showCursor, hasCompletedTyping, isCursorEnabled])\n\n return <Text>{displayText}</Text>\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { mapChars } from '../utils/text.js'\n\ntype WaveType = 'brightness' | 'vertical'\n\ninterface WaveProps extends BaseEffectProps {\n /**\n * Gradient colours for the wave [dark, bright]\n * @default ['#888888', '#ffffff']\n * @example ['#ec4899', '#8b5cf6']\n */\n colors?: [Colour, Colour]\n\n /**\n * Wave height (0-1)\n * @default 0.5\n */\n amplitude?: number\n\n /**\n * Number of wave cycles across text\n * @default 2\n */\n frequency?: number\n\n /**\n * Wave effect type\n * @default 'brightness'\n */\n type?: WaveType\n}\n\nconst DEFAULT_COLORS: [Colour, Colour] = ['#888888', '#ffffff']\nconst DEFAULT_AMPLITUDE = 0.5\nconst DEFAULT_FREQUENCY = 2\nconst DEFAULT_TYPE: WaveType = 'brightness'\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst WAVE_PERIOD_MS = 2000\nconst MIN_AMPLITUDE = 0\nconst MAX_AMPLITUDE = 1\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst VERTICAL_SHIFT_THRESHOLD = 0.5\n\nfunction calculateWaveValue(\n characterIndex: number,\n time: number,\n frequency: number,\n amplitude: number,\n): number {\n const clampedAmplitude = clamp(amplitude, MIN_AMPLITUDE, MAX_AMPLITUDE)\n const safeFrequency = frequency || DEFAULT_FREQUENCY\n const waveLength = FULL_CIRCLE_RADIANS / safeFrequency\n const spatialComponent = (characterIndex / waveLength) * FULL_CIRCLE_RADIANS\n const temporalComponent = time * FULL_CIRCLE_RADIANS\n const phase = spatialComponent - temporalComponent\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const amplitudeComplement = MAX_AMPLITUDE - clampedAmplitude\n return normalizedSine * clampedAmplitude + amplitudeComplement\n}\n\n/**\n * Wave effect component that creates a wave motion through text\n *\n * Animates text with a sine wave pattern that can affect brightness or vertical position.\n * The wave continuously flows through the text.\n *\n * @example\n * ```tsx\n * <Wave colors={['#ec4899', '#8b5cf6']} amplitude={0.7} frequency={3}>\n * ~~ wavy text ~~\n * </Wave>\n * ```\n */\nexport function Wave({\n children,\n colors = DEFAULT_COLORS,\n amplitude = DEFAULT_AMPLITUDE,\n frequency = DEFAULT_FREQUENCY,\n type = DEFAULT_TYPE,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: WaveProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const normalizedTime = elapsedTime / WAVE_PERIOD_MS\n\n const waveText = useMemo(() => {\n if (type === 'brightness') {\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const [darkColor, brightColor] = colors\n const characterColor = interpolateColor(darkColor, brightColor, waveValue)\n return colorize(character, characterColor)\n })\n }\n\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const shouldShift = waveValue > VERTICAL_SHIFT_THRESHOLD\n return shouldShift ? ` ${character}` : character\n })\n }, [children, normalizedTime, colors, amplitude, frequency, type])\n\n return <Text>{waveText}</Text>\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useAnimationFrame.ts","../src/hooks/useElapsedTime.ts","../src/utils/colors.ts","../src/utils/easing.ts","../src/components/Fade.tsx","../src/components/Flash.tsx","../src/utils/text.ts","../src/components/Shimmer.tsx","../src/hooks/useCursorBlink.ts","../src/hooks/useTypewriterProgress.ts","../src/components/Typewriter.tsx","../src/components/Wave.tsx"],"names":["useRef","useEffect","useState","chalk","useMemo","jsx","Text","DEFAULT_DURATION_MS","DEFAULT_SPEED","MIN_INTENSITY","MAX_INTENSITY","FIRST_CHARACTER_INDEX","DEFAULT_COLORS","FULL_CIRCLE_RADIANS","SINE_WAVE_OFFSET","SINE_WAVE_NORMALIZE"],"mappings":";;;;;;;;;;;;AAEA,IAAM,UAAA,GAAa,EAAA;AACnB,IAAM,oBAAoB,GAAA,GAAO,UAAA;AAQ1B,SAAS,iBAAA,CACd,QAAA,EACA,OAAA,GAAmB,IAAA,EACb;AACN,EAAA,MAAM,cAAcA,YAAA,EAAc;AAClC,EAAA,MAAM,kBAAkBA,YAAA,EAAe;AACvC,EAAA,MAAM,WAAA,GAAcA,aAAO,QAAQ,CAAA;AAEnC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,WAAA,CAAY,OAAA,GAAU,QAAA;AAAA,EACxB,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,IAAI,YAAY,OAAA,EAAS;AACvB,QAAA,aAAA,CAAc,YAAY,OAAO,CAAA;AAAA,MACnC;AACA,MAAA,eAAA,CAAgB,OAAA,GAAU,MAAA;AAC1B,MAAA;AAAA,IACF;AAEA,IAAA,WAAA,CAAY,OAAA,GAAU,YAAY,MAAM;AACtC,MAAA,MAAM,WAAA,GAAc,KAAK,GAAA,EAAI;AAC7B,MAAA,IAAI,eAAA,CAAgB,YAAY,MAAA,EAAW;AACzC,QAAA,MAAM,SAAA,GAAY,cAAc,eAAA,CAAgB,OAAA;AAChD,QAAA,WAAA,CAAY,QAAQ,SAAS,CAAA;AAAA,MAC/B;AACA,MAAA,eAAA,CAAgB,OAAA,GAAU,WAAA;AAAA,IAC5B,GAAG,iBAAiB,CAAA;AAEpB,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,YAAY,OAAA,EAAS;AACvB,QAAA,aAAA,CAAc,YAAY,OAAO,CAAA;AAAA,MACnC;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AACd;;;ACrCO,SAAS,cAAA,CACd,OAAA,GAAmB,IAAA,EACnB,KAAA,GAAgB,CAAA,EACR;AACR,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIC,eAAS,CAAC,CAAA;AAEhD,EAAA,iBAAA,CAAkB,CAAC,SAAA,KAAc;AAC/B,IAAA,cAAA,CAAe,CAAA,IAAA,KAAQ,IAAA,GAAO,SAAA,GAAY,KAAK,CAAA;AAAA,EACjD,GAAG,OAAO,CAAA;AAEV,EAAA,OAAO,WAAA;AACT;AClBA,IAAM,QAAA,GAAW,EAAA;AACjB,IAAM,YAAA,GAAe,EAAA;AACrB,IAAM,eAAA,GAAkB,CAAA;AACxB,IAAM,iBAAA,GAAoB,GAAA;AAC1B,IAAM,kBAAA,GAAqB,CAAA;AAC3B,IAAM,sBAAA,GAAyB,GAAA;AAE/B,IAAM,eAAA,GAAkB,2CAAA;AACxB,IAAM,iBAAA,GAAoB,MAAA;AAE1B,SAAS,QAAA,CAAS,GAAA,EAAa,KAAA,EAAe,IAAA,EAAsB;AAClE,EAAA,MAAM,SAAS,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAA,CAAE,QAAA,CAAS,iBAAiB,iBAAiB,CAAA;AACjF,EAAA,MAAM,WAAW,KAAA,CAAM,QAAA,CAAS,QAAQ,CAAA,CAAE,QAAA,CAAS,iBAAiB,iBAAiB,CAAA;AACrF,EAAA,MAAM,UAAU,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,CAAE,QAAA,CAAS,iBAAiB,iBAAiB,CAAA;AACnF,EAAA,OAAO,CAAA,CAAA,EAAI,MAAM,CAAA,EAAG,QAAQ,GAAG,OAAO,CAAA,CAAA;AACxC;AAQO,SAAS,SAAS,GAAA,EAA8C;AACrE,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,CAAK,GAAG,CAAA;AACvC,EAAA,IAAI,CAAC,MAAA;AACH,IAAA,OAAO,IAAA;AAET,EAAA,MAAM,GAAG,MAAA,EAAQ,QAAA,EAAU,OAAO,CAAA,GAAI,MAAA;AACtC,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,QAAA,IAAY,CAAC,OAAA;AAC3B,IAAA,OAAO,IAAA;AAET,EAAA,OAAO;AAAA,IACL,MAAA,CAAO,QAAA,CAAS,MAAA,EAAQ,QAAQ,CAAA;AAAA,IAChC,MAAA,CAAO,QAAA,CAAS,QAAA,EAAU,QAAQ,CAAA;AAAA,IAClC,MAAA,CAAO,QAAA,CAAS,OAAA,EAAS,QAAQ;AAAA,GACnC;AACF;AASO,SAAS,QAAA,CAAS,MAAc,KAAA,EAAsB;AAC3D,EAAA,IAAI;AACF,IAAA,IAAI,KAAA,CAAM,WAAW,GAAG,CAAA;AACtB,MAAA,OAAOC,sBAAA,CAAM,GAAA,CAAI,KAAK,CAAA,CAAE,IAAI,CAAA;AAE9B,IAAA,IAAI,KAAA,CAAM,UAAA,CAAW,KAAK,CAAA,EAAG;AAC3B,MAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,iBAAiB,CAAA;AAC3C,MAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,MAAA,GAAS,kBAAA;AAC3B,QAAA,OAAO,IAAA;AAET,MAAA,MAAM,CAAC,MAAA,EAAQ,QAAA,EAAU,OAAO,CAAA,GAAI,KAAA;AACpC,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,QAAA,IAAY,CAAC,OAAA;AAC3B,QAAA,OAAO,IAAA;AAET,MAAA,MAAM,GAAA,GAAM,MAAA,CAAO,QAAA,CAAS,MAAA,EAAQ,YAAY,CAAA;AAChD,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,QAAA,CAAS,QAAA,EAAU,YAAY,CAAA;AACpD,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,QAAA,CAAS,OAAA,EAAS,YAAY,CAAA;AAElD,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,IAAK,MAAA,CAAO,MAAM,KAAK,CAAA,IAAK,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AAC/D,QAAA,OAAO,IAAA;AAET,MAAA,OAAOA,uBAAM,GAAA,CAAI,GAAA,EAAK,KAAA,EAAO,IAAI,EAAE,IAAI,CAAA;AAAA,IACzC;AAEA,IAAA,MAAM,UAAA,GAAcA,uBAAc,KAAK,CAAA;AACvC,IAAA,IAAI,OAAO,UAAA,KAAe,UAAA;AACxB,MAAA,OAAO,WAAW,IAAI,CAAA;AAExB,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MACM;AACJ,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAUO,SAAS,YAAA,CAAa,OAAc,OAAA,EAAwB;AACjE,EAAA,IAAI,CAAC,KAAA,CAAM,UAAA,CAAW,GAAG,CAAA;AACvB,IAAA,OAAO,KAAA;AAET,EAAA,MAAM,GAAA,GAAM,SAAS,KAAK,CAAA;AAC1B,EAAA,IAAI,CAAC,GAAA;AACH,IAAA,OAAO,KAAA;AAET,EAAA,MAAM,CAAC,GAAA,EAAK,KAAA,EAAO,IAAI,CAAA,GAAI,GAAA;AAC3B,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,OAAO,CAAA;AAC5C,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,OAAO,CAAA;AAChD,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,OAAO,CAAA;AAE9C,EAAA,OAAO,QAAA,CAAS,WAAA,EAAa,aAAA,EAAe,YAAY,CAAA;AAC1D;AAUO,SAAS,gBAAA,CACd,MAAA,EACA,MAAA,EACA,QAAA,EACO;AACP,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,UAAA,CAAW,GAAG,CAAA;AACzC,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,UAAA,CAAW,GAAG,CAAA;AAEzC,EAAA,IAAI,CAAC,eAAe,CAAC,WAAA;AACnB,IAAA,OAAO,QAAA,GAAW,yBAAyB,MAAA,GAAS,MAAA;AAEtD,EAAA,MAAM,IAAA,GAAO,SAAS,MAAM,CAAA;AAC5B,EAAA,MAAM,IAAA,GAAO,SAAS,MAAM,CAAA;AAE5B,EAAA,IAAI,CAAC,QAAQ,CAAC,IAAA;AACZ,IAAA,OAAO,QAAA,GAAW,yBAAyB,MAAA,GAAS,MAAA;AAEtD,EAAA,MAAM,CAAC,IAAA,EAAM,MAAA,EAAQ,KAAK,CAAA,GAAI,IAAA;AAC9B,EAAA,MAAM,CAAC,IAAA,EAAM,MAAA,EAAQ,KAAK,CAAA,GAAI,IAAA;AAE9B,EAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,IAAA,GAAA,CAAQ,IAAA,GAAO,QAAQ,QAAQ,CAAA;AACtD,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,MAAA,GAAA,CAAU,MAAA,GAAS,UAAU,QAAQ,CAAA;AAC9D,EAAA,MAAM,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAA,CAAS,KAAA,GAAQ,SAAS,QAAQ,CAAA;AAE1D,EAAA,OAAO,QAAA,CAAS,GAAA,EAAK,KAAA,EAAO,IAAI,CAAA;AAClC;;;AC3IO,IAAM,SAAyB,CAAA,IAAA,KAAQ,IAAA;AAEvC,IAAM,MAAA,GAAyB,UAAQ,IAAA,GAAO,IAAA;AAE9C,IAAM,OAAA,GAA0B,CAAA,IAAA,KAAQ,IAAA,IAAQ,CAAA,GAAI,IAAA,CAAA;AAEpD,IAAM,SAAA,GAA4B,CAAC,IAAA,KAAS;AACjD,EAAA,OAAO,IAAA,GAAO,MACV,CAAA,GAAI,IAAA,GAAO,OACX,EAAA,GAAA,CAAM,CAAA,GAAI,IAAI,IAAA,IAAQ,IAAA;AAC5B,CAAA;AAEO,IAAM,MAAA,GAAyB,UAAQ,CAAA,GAAI,IAAA,CAAK,IAAK,IAAA,GAAO,IAAA,CAAK,KAAM,CAAC,CAAA;AAExE,IAAM,UAA0B,CAAA,IAAA,KAAQ,IAAA,CAAK,IAAK,IAAA,GAAO,IAAA,CAAK,KAAM,CAAC,CAAA;AAErE,IAAM,SAAA,GAA4B,UAAQ,EAAE,IAAA,CAAK,IAAI,IAAA,CAAK,EAAA,GAAK,IAAI,CAAA,GAAI,CAAA,CAAA,GAAK,CAAA;AAE5E,IAAM,eAAA,GAAsD;AAAA,EACjE,QAAA,EAAU,MAAA;AAAA,EACV,SAAA,EAAW,MAAA;AAAA,EACX,UAAA,EAAY,OAAA;AAAA,EACZ,aAAA,EAAe,SAAA;AAAA,EACf,SAAA,EAAW,MAAA;AAAA,EACX,UAAA,EAAY,OAAA;AAAA,EACZ,aAAA,EAAe;AACjB,CAAA;AAEO,SAAS,iBAAA,CAAkB,OAAmB,QAAA,EAA0B;AAC7E,EAAA,OAAO,gBAAgB,IAAI,CAAA;AAC7B;AAEO,SAAS,KAAA,CAAM,KAAA,EAAe,GAAA,EAAa,GAAA,EAAqB;AACrE,EAAA,OAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,KAAA,EAAO,GAAG,GAAG,GAAG,CAAA;AAC3C;ACUA,IAAM,YAAA,GAAe,CAAA;AACrB,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,mBAAA,GAAsB,GAAA;AAC5B,IAAM,cAAA,GAA6B,aAAA;AACnC,IAAM,YAAA,GAAe,KAAA;AACrB,IAAM,aAAA,GAAgB,CAAA;AAEtB,SAAS,gBAAA,CACP,WAAA,EACA,QAAA,EACA,IAAA,EACA,IACA,MAAA,EACQ;AACR,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,WAAA,GAAc,UAAU,CAAC,CAAA;AACnD,EAAA,MAAM,aAAA,GAAgB,iBAAA,CAAkB,MAAM,CAAA,CAAE,QAAQ,CAAA;AACxD,EAAA,OAAO,IAAA,GAAA,CAAQ,KAAK,IAAA,IAAQ,aAAA;AAC9B;AAmBO,SAAS,IAAA,CAAK;AAAA,EACnB,QAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA,GAAO,YAAA;AAAA,EACP,EAAA,GAAK,UAAA;AAAA,EACL,QAAA,GAAW,mBAAA;AAAA,EACX,MAAA,GAAS,cAAA;AAAA,EACT,IAAA,GAAO,YAAA;AAAA,EACP,KAAA,GAAQ,aAAA;AAAA,EACR,OAAA,GAAU,IAAA;AAAA,EACV;AACF,CAAA,EAAc;AACZ,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAID,eAAS,KAAK,CAAA;AACtD,EAAA,MAAM,WAAA,GAAc,cAAA,CAAe,OAAA,IAAW,CAAC,cAAc,KAAK,CAAA;AAElE,EAAAD,gBAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA;AACH,MAAA;AAEF,IAAA,MAAM,aAAa,WAAA,IAAe,QAAA;AAElC,IAAA,IAAI,UAAA,IAAc,CAAC,IAAA,IAAQ,CAAC,YAAA,EAAc;AAExC,MAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,MAAA,UAAA,IAAa;AAAA,IACf;AAAA,EACF,CAAA,EAAG,CAAC,WAAA,EAAa,QAAA,EAAU,MAAM,YAAA,EAAc,OAAA,EAAS,UAAU,CAAC,CAAA;AAEnE,EAAA,MAAM,SAAA,GAAYG,cAAQ,MAAM;AAC9B,IAAA,IAAI,aAAA,GAAgB,WAAA;AACpB,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,MAAM,SAAA,GAAY,eAAe,QAAA,GAAW,CAAA,CAAA;AAC5C,MAAA,aAAA,GAAgB,SAAA,GAAY,QAAA,GAAY,QAAA,GAAW,CAAA,GAAK,SAAA,GAAY,SAAA;AAAA,IACtE,CAAA,MACK;AACH,MAAA,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,WAAA,EAAa,QAAQ,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,UAAU,gBAAA,CAAiB,aAAA,EAAe,QAAA,EAAU,IAAA,EAAM,IAAI,MAAM,CAAA;AAE1E,IAAA,IAAI,UAAU,IAAA,EAAM;AAClB,MAAA,OAAO,EAAA;AAAA,IACT;AAEA,IAAA,MAAM,YAAY,KAAA,IAAS,SAAA;AAC3B,IAAA,MAAM,iBAAiB,OAAA,IAAW,GAAA;AAClC,IAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,SAAA,EAAW,SAAA,EAAW,cAAc,CAAA;AAExE,IAAA,OAAO,QAAA,CAAS,UAAU,UAAU,CAAA;AAAA,EACtC,CAAA,EAAG,CAAC,QAAA,EAAU,WAAA,EAAa,QAAA,EAAU,MAAM,EAAA,EAAI,MAAA,EAAQ,KAAA,EAAO,IAAI,CAAC,CAAA;AAEnE,EAAA,uBAAOC,cAAA,CAACC,YAAM,QAAA,EAAA,SAAA,EAAU,CAAA;AAC1B;ACpGA,IAAM,aAAA,GAAgB,SAAA;AACtB,IAAM,qBAAA,GAAwB,GAAA;AAC9B,IAAM,qBAAA,GAAwB,CAAA;AAC9B,IAAMC,oBAAAA,GAAsB,GAAA;AAC5B,IAAMC,cAAAA,GAAgB,CAAA;AACtB,IAAM,mBAAA,GAAsB,KAAK,EAAA,GAAK,CAAA;AACtC,IAAM,gBAAA,GAAmB,CAAA;AACzB,IAAM,mBAAA,GAAsB,GAAA;AAC5B,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAM,aAAA,GAAgB,CAAA;AAEtB,SAAS,uBAAA,CACP,IAAA,EACA,QAAA,EACA,YAAA,EACA,YAAA,EACQ;AACR,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,YAAA,EAAc,aAAA,EAAe,aAAa,CAAA;AACnE,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,YAAA,EAAc,aAAA,EAAe,aAAa,CAAA;AACnE,EAAA,MAAM,iBAAiB,IAAA,GAAO,QAAA;AAC9B,EAAA,MAAM,QAAQ,cAAA,GAAiB,mBAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,EAAA,MAAM,cAAA,GAAA,CAAkB,WAAW,gBAAA,IAAoB,mBAAA;AACvD,EAAA,MAAM,iBAAiB,UAAA,GAAa,UAAA;AACpC,EAAA,OAAO,aAAa,cAAA,GAAiB,cAAA;AACvC;AAgBO,SAAS,KAAA,CAAM;AAAA,EACpB,QAAA;AAAA,EACA,KAAA,GAAQ,aAAA;AAAA,EACR,YAAA,GAAe,qBAAA;AAAA,EACf,YAAA,GAAe,qBAAA;AAAA,EACf,QAAA,GAAWD,oBAAAA;AAAA,EACX,KAAA,GAAQC,cAAAA;AAAA,EACR,OAAA,GAAU;AACZ,CAAA,EAAe;AACb,EAAA,MAAM,WAAA,GAAc,cAAA,CAAe,OAAA,EAAS,KAAK,CAAA;AACjD,EAAA,MAAM,YAAY,WAAA,GAAc,QAAA;AAEhC,EAAA,MAAM,SAAA,GAAYJ,cAAQ,MAAM;AAC9B,IAAA,MAAM,SAAA,GAAY,uBAAA,CAAwB,SAAA,EAAW,QAAA,EAAU,cAAc,YAAY,CAAA;AACzF,IAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,KAAA,EAAO,SAAS,CAAA;AACnD,IAAA,OAAO,QAAA,CAAS,UAAU,aAAa,CAAA;AAAA,EACzC,CAAA,EAAG,CAAC,QAAA,EAAU,SAAA,EAAW,UAAU,YAAA,EAAc,YAAA,EAAc,KAAK,CAAC,CAAA;AAErE,EAAA,uBAAOC,cAAAA,CAACC,QAAAA,EAAA,EAAM,QAAA,EAAA,SAAA,EAAU,CAAA;AAC1B;;;AC9FO,SAAS,WAAW,IAAA,EAAwB;AACjD,EAAA,OAAO,CAAC,GAAG,IAAI,CAAA;AACjB;AAEO,SAAS,cAAc,IAAA,EAAsB;AAClD,EAAA,OAAO,CAAC,GAAG,IAAI,CAAA,CAAE,MAAA;AACnB;AAEO,SAAS,QAAA,CACd,MACA,EAAA,EACQ;AACR,EAAA,OAAO,WAAW,IAAI,CAAA,CAAE,IAAI,EAAE,CAAA,CAAE,KAAK,EAAE,CAAA;AACzC;ACwBA,IAAM,cAAA,GAAwC,CAAC,SAAA,EAAW,SAAA,EAAW,SAAS,CAAA;AAC9E,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAM,iBAAA,GAAoB,CAAA;AAC1B,IAAM,iBAAA,GAAsC,OAAA;AAC5C,IAAME,cAAAA,GAAgB,CAAA;AACtB,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,0BAAA,GAA6B,GAAA;AACnC,IAAM,0BAAA,GAA6B,CAAA;AACnC,IAAMC,cAAAA,GAAgB,CAAA;AACtB,IAAMC,cAAAA,GAAgB,CAAA;AAef,SAAS,OAAA,CAAQ;AAAA,EACtB,QAAA;AAAA,EACA,MAAA,GAAS,cAAA;AAAA,EACT,KAAA,GAAQ,aAAA;AAAA,EACR,SAAA,GAAY,iBAAA;AAAA,EACZ,SAAA,GAAY,iBAAA;AAAA,EACZ,KAAA,GAAQF,cAAAA;AAAA,EACR,OAAA,GAAU,IAAA;AAAA,EACV;AACF,CAAA,EAAiB;AACf,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIN,eAAS,CAAC,CAAA;AACtC,EAAA,MAAM,UAAA,GAAa,cAAc,QAAQ,CAAA;AACzC,EAAA,MAAM,aAAa,UAAA,GAAa,KAAA;AAEhC,EAAA,iBAAA,CAAkB,CAAC,SAAA,KAAc;AAC/B,IAAA,SAAA,CAAU,CAAC,cAAA,KAAmB;AAC5B,MAAA,MAAM,QAAA,GAAY,SAAA,GAAY,kBAAA,GAAsB,KAAA,GAAQ,UAAA;AAC5D,MAAA,MAAM,SAAA,GAAY,SAAA,KAAc,OAAA,GAC5B,cAAA,GAAiB,WACjB,cAAA,GAAiB,QAAA;AAErB,MAAA,MAAM,iBAAA,GAAoB,IAAA,CAAK,GAAA,CAAI,SAAS,CAAA,IAAK,UAAA;AACjD,MAAA,IAAI,iBAAA,EAAmB;AACrB,QAAA,UAAA,IAAa;AACb,QAAA,OAAO,CAAA;AAAA,MACT;AAEA,MAAA,OAAO,SAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,GAAG,OAAO,CAAA;AAEV,EAAA,MAAM,WAAA,GAAcE,cAAQ,MAAM;AAChC,IAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAC,IAAA,EAAM,KAAA,KAAU;AACzC,MAAA,MAAM,gBAAA,GAAmB,SAAA,KAAc,OAAA,GAAU,MAAA,GAAS,UAAA,GAAa,MAAA;AACvE,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,gBAAgB,CAAA;AAElD,MAAA,MAAM,uBAAuB,QAAA,GAAW,KAAA;AACxC,MAAA,MAAM,aAAA,GAAgB,oBAAA,GAClB,QAAA,GAAW,KAAA,GACX,CAAA;AAEJ,MAAA,MAAM,CAAC,UAAA,EAAY,SAAA,EAAW,QAAQ,CAAA,GAAI,MAAA;AAC1C,MAAA,MAAM,iBAAA,GAAoB,KAAA,CAAM,SAAA,EAAWK,cAAAA,EAAeC,cAAa,CAAA;AAEvE,MAAA,MAAM,cAAc,aAAA,GAAgB,0BAAA;AACpC,MAAA,MAAM,eAAe,WAAA,GACjB,gBAAA;AAAA,QACE,UAAA;AAAA,QACA,SAAA;AAAA,QACA,gBAAgB,0BAAA,GAA6B;AAAA,OAC/C,GACA,gBAAA;AAAA,QACE,SAAA;AAAA,QACA,QAAA;AAAA,QAAA,CACC,aAAA,GAAgB,8BAA8B,0BAAA,GAA6B;AAAA,OAC9E;AAEJ,MAAA,OAAO,QAAA,CAAS,MAAM,YAAY,CAAA;AAAA,IACpC,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,QAAA,EAAU,MAAA,EAAQ,QAAQ,KAAA,EAAO,SAAA,EAAW,SAAA,EAAW,UAAU,CAAC,CAAA;AAEtE,EAAA,uBAAOL,cAAAA,CAACC,QAAAA,EAAA,EAAM,QAAA,EAAA,WAAA,EAAY,CAAA;AAC5B;ACzHA,IAAM,wBAAA,GAA2B,GAAA;AAe1B,SAAS,cAAA,CAAe;AAAA,EAC7B,OAAA;AAAA,EACA;AACF,CAAA,EAAmC;AACjC,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIJ,eAAS,IAAI,CAAA;AACjD,EAAA,MAAM,cAAcF,YAAAA,EAAc;AAElC,EAAAC,gBAAU,MAAM;AACd,IAAA,IAAI,CAAC,WAAW,UAAA,EAAY;AAE1B,MAAA,aAAA,CAAc,KAAK,CAAA;AACnB,MAAA;AAAA,IACF;AAEA,IAAA,WAAA,CAAY,OAAA,GAAU,YAAY,MAAM;AACtC,MAAA,aAAA,CAAc,CAAA,QAAA,KAAY,CAAC,QAAQ,CAAA;AAAA,IACrC,GAAG,wBAAwB,CAAA;AAE3B,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,WAAA,CAAY,OAAA;AACd,QAAA,aAAA,CAAc,YAAY,OAAO,CAAA;AAAA,IACrC,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,UAAU,CAAC,CAAA;AAExB,EAAA,OAAO,UAAA;AACT;ACvCA,IAAM,uBAAA,GAA0B,EAAA;AAChC,IAAM,YAAA,GAAe,CAAA;AACrB,IAAM,YAAA,GAAe,CAAA;AACrB,IAAM,qBAAA,GAAwB,CAAA;AAE9B,SAAS,uBAAA,CACP,OACA,QAAA,EACQ;AACR,EAAA,MAAM,eAAA,GAAkB,KAAA,CAAM,QAAA,EAAU,YAAA,EAAc,YAAY,CAAA;AAClE,EAAA,MAAM,cAAA,GAAA,CAAkB,IAAA,CAAK,MAAA,EAAO,GAAI,GAAA,IAAO,eAAA;AAC/C,EAAA,OAAQ,uBAAA,GAA0B,SAAU,CAAA,GAAI,cAAA,CAAA;AAClD;AAuBO,SAAS,qBAAA,CAAsB;AAAA,EACpC,eAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAyC;AACvC,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAIC,eAAS,CAAC,CAAA;AAC5D,EAAA,MAAM,aAAaF,YAAAA,EAAc;AACjC,EAAA,MAAM,qBAAqB,iBAAA,IAAqB,eAAA;AAEhD,EAAAC,gBAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA;AACH,MAAA;AAEF,IAAA,IAAI,kBAAA,EAAoB;AACtB,MAAA,UAAA,IAAa;AACb,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,cAAA,GAAiB,uBAAA,CAAwB,KAAA,EAAO,QAAQ,CAAA;AAC9D,IAAA,MAAM,mBAAmB,iBAAA,KAAsB,qBAAA;AAC/C,IAAA,MAAM,UAAA,GAAa,gBAAA,GAAmB,YAAA,GAAe,cAAA,GAAiB,cAAA;AAEtE,IAAA,UAAA,CAAW,OAAA,GAAU,WAAW,MAAM;AACpC,MAAA,oBAAA,CAAqB,CAAA,QAAA,KAAY,WAAW,CAAC,CAAA;AAAA,IAC/C,GAAG,UAAU,CAAA;AAEb,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,UAAA,CAAW,OAAA;AACb,QAAA,YAAA,CAAa,WAAW,OAAO,CAAA;AAAA,IACnC,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,iBAAA,EAAmB,OAAA,EAAS,OAAO,QAAA,EAAU,YAAA,EAAc,kBAAA,EAAoB,UAAU,CAAC,CAAA;AAE9F,EAAA,OAAO,iBAAA;AACT;AC/BA,IAAM,cAAA,GAAiB,QAAA;AACvB,IAAM,gBAAA,GAAmB,GAAA;AACzB,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAMO,cAAAA,GAAgB,CAAA;AACtB,IAAMG,sBAAAA,GAAwB,CAAA;AAE9B,SAAS,mBAAmB,MAAA,EAAkC;AAC5D,EAAA,OAAO,OAAO,MAAA,KAAW,QAAA,GAAW,MAAA,GAAS,cAAA;AAC/C;AAEA,SAAS,YAAA,CACP,eAAA,EACA,WAAA,EACA,SAAA,EACQ;AACR,EAAA,IAAI,WAAA;AACF,IAAA,OAAO,QAAA,CAAS,iBAAiB,WAAW,CAAA;AAE9C,EAAA,IAAI,SAAA;AACF,IAAA,OAAO,QAAA,CAAS,iBAAiB,SAAS,CAAA;AAE5C,EAAA,OAAO,eAAA;AACT;AAeO,SAAS,UAAA,CAAW;AAAA,EACzB,QAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA,GAAS,cAAA;AAAA,EACT,WAAA;AAAA,EACA,QAAA,GAAW,gBAAA;AAAA,EACX,KAAA,GAAQ,aAAA;AAAA,EACR,KAAA,GAAQH,cAAAA;AAAA,EACR,OAAA,GAAU,IAAA;AAAA,EACV;AACF,CAAA,EAAoB;AAClB,EAAA,MAAM,UAAA,GAAa,WAAW,QAAQ,CAAA;AACtC,EAAA,MAAM,eAAA,GAAkB,cAAc,QAAQ,CAAA;AAE9C,EAAA,MAAM,oBAAoB,qBAAA,CAAsB;AAAA,IAC9C,eAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA,EAAc,KAAA;AAAA,IACd,OAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,qBAAqB,iBAAA,IAAqB,eAAA;AAChD,EAAA,MAAM,kBAAkB,MAAA,KAAW,KAAA;AAEnC,EAAA,MAAM,aAAa,cAAA,CAAe;AAAA,IAChC,SAAS,OAAA,IAAW,eAAA;AAAA,IACpB,UAAA,EAAY;AAAA,GACb,CAAA;AAED,EAAA,MAAM,WAAA,GAAcJ,cAAQ,MAAM;AAChC,IAAA,MAAM,cAAc,UAAA,CAAW,KAAA,CAAMO,wBAAuB,iBAAiB,CAAA,CAAE,KAAK,EAAE,CAAA;AACtF,IAAA,MAAM,WAAA,GAAc,KAAA,GAAQ,QAAA,CAAS,WAAA,EAAa,KAAK,CAAA,GAAI,WAAA;AAE3D,IAAA,MAAM,gBAAA,GAAmB,eAAA,IAAmB,UAAA,IAAc,CAAC,kBAAA;AAC3D,IAAA,IAAI,CAAC,gBAAA;AACH,MAAA,OAAO,WAAA;AAET,IAAA,MAAM,eAAA,GAAkB,mBAAmB,MAAM,CAAA;AACjD,IAAA,MAAM,UAAA,GAAa,YAAA,CAAa,eAAA,EAAiB,WAAA,EAAa,KAAK,CAAA;AAEnE,IAAA,OAAO,WAAA,GAAc,UAAA;AAAA,EACvB,CAAA,EAAG,CAAC,UAAA,EAAY,iBAAA,EAAmB,KAAA,EAAO,QAAQ,WAAA,EAAa,UAAA,EAAY,kBAAA,EAAoB,eAAe,CAAC,CAAA;AAE/G,EAAA,uBAAON,cAAAA,CAACC,QAAAA,EAAA,EAAM,QAAA,EAAA,WAAA,EAAY,CAAA;AAC5B;ACzFA,IAAMM,eAAAA,GAAiC,CAAC,SAAA,EAAW,SAAS,CAAA;AAC5D,IAAM,iBAAA,GAAoB,GAAA;AAC1B,IAAM,iBAAA,GAAoB,CAAA;AAC1B,IAAM,YAAA,GAAyB,YAAA;AAC/B,IAAMJ,cAAAA,GAAgB,CAAA;AACtB,IAAMK,oBAAAA,GAAsB,KAAK,EAAA,GAAK,CAAA;AACtC,IAAM,cAAA,GAAiB,GAAA;AACvB,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAMC,iBAAAA,GAAmB,CAAA;AACzB,IAAMC,oBAAAA,GAAsB,GAAA;AAC5B,IAAM,wBAAA,GAA2B,GAAA;AAEjC,SAAS,kBAAA,CACP,cAAA,EACA,IAAA,EACA,SAAA,EACA,SAAA,EACQ;AACR,EAAA,MAAM,gBAAA,GAAmB,KAAA,CAAM,SAAA,EAAW,aAAA,EAAe,aAAa,CAAA;AACtE,EAAA,MAAM,gBAAgB,SAAA,IAAa,iBAAA;AACnC,EAAA,MAAM,aAAaF,oBAAAA,GAAsB,aAAA;AACzC,EAAA,MAAM,gBAAA,GAAoB,iBAAiB,UAAA,GAAcA,oBAAAA;AACzD,EAAA,MAAM,oBAAoB,IAAA,GAAOA,oBAAAA;AACjC,EAAA,MAAM,QAAQ,gBAAA,GAAmB,iBAAA;AACjC,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,EAAA,MAAM,cAAA,GAAA,CAAkB,WAAWC,iBAAAA,IAAoBC,oBAAAA;AACvD,EAAA,MAAM,sBAAsB,aAAA,GAAgB,gBAAA;AAC5C,EAAA,OAAO,iBAAiB,gBAAA,GAAmB,mBAAA;AAC7C;AAeO,SAAS,IAAA,CAAK;AAAA,EACnB,QAAA;AAAA,EACA,MAAA,GAASH,eAAAA;AAAA,EACT,SAAA,GAAY,iBAAA;AAAA,EACZ,SAAA,GAAY,iBAAA;AAAA,EACZ,IAAA,GAAO,YAAA;AAAA,EACP,KAAA,GAAQJ,cAAAA;AAAA,EACR,OAAA,GAAU;AACZ,CAAA,EAAc;AACZ,EAAA,MAAM,WAAA,GAAc,cAAA,CAAe,OAAA,EAAS,KAAK,CAAA;AACjD,EAAA,MAAM,iBAAiB,WAAA,GAAc,cAAA;AAErC,EAAA,MAAM,QAAA,GAAWJ,cAAQ,MAAM;AAC7B,IAAA,IAAI,SAAS,YAAA,EAAc;AACzB,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAC,SAAA,EAAW,KAAA,KAAU;AAC9C,QAAA,MAAM,SAAA,GAAY,kBAAA,CAAmB,KAAA,EAAO,cAAA,EAAgB,WAAW,SAAS,CAAA;AAChF,QAAA,MAAM,CAAC,SAAA,EAAW,WAAW,CAAA,GAAI,MAAA;AACjC,QAAA,MAAM,cAAA,GAAiB,gBAAA,CAAiB,SAAA,EAAW,WAAA,EAAa,SAAS,CAAA;AACzE,QAAA,OAAO,QAAA,CAAS,WAAW,cAAc,CAAA;AAAA,MAC3C,CAAC,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAC,SAAA,EAAW,KAAA,KAAU;AAC9C,MAAA,MAAM,SAAA,GAAY,kBAAA,CAAmB,KAAA,EAAO,cAAA,EAAgB,WAAW,SAAS,CAAA;AAChF,MAAA,MAAM,cAAc,SAAA,GAAY,wBAAA;AAChC,MAAA,OAAO,WAAA,GAAc,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,GAAK,SAAA;AAAA,IACzC,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,QAAA,EAAU,cAAA,EAAgB,QAAQ,SAAA,EAAW,SAAA,EAAW,IAAI,CAAC,CAAA;AAEjE,EAAA,uBAAOC,cAAAA,CAACC,QAAAA,EAAA,EAAM,QAAA,EAAA,QAAA,EAAS,CAAA;AACzB","file":"index.cjs","sourcesContent":["import { useEffect, useRef } from 'react'\n\nconst TARGET_FPS = 60\nconst FRAME_INTERVAL_MS = 1000 / TARGET_FPS\n\n/**\n * Runs a callback on every animation frame using setInterval\n *\n * @param callback - Function called each frame with delta time in ms\n * @param enabled - Whether animation is active\n */\nexport function useAnimationFrame(\n callback: (deltaTime: number) => void,\n enabled: boolean = true,\n): void {\n const intervalRef = useRef<Timer>()\n const previousTimeRef = useRef<number>()\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n previousTimeRef.current = undefined\n return\n }\n\n intervalRef.current = setInterval(() => {\n const currentTime = Date.now()\n if (previousTimeRef.current !== undefined) {\n const deltaTime = currentTime - previousTimeRef.current\n callbackRef.current(deltaTime)\n }\n previousTimeRef.current = currentTime\n }, FRAME_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [enabled])\n}\n","import { useState } from 'react'\nimport { useAnimationFrame } from './useAnimationFrame.js'\n\n/**\n * Hook that tracks elapsed time since mount or last reset\n *\n * @param enabled - Whether to track time\n * @param speed - Speed multiplier (default: 1)\n * @returns Elapsed time in milliseconds\n */\nexport function useElapsedTime(\n enabled: boolean = true,\n speed: number = 1,\n): number {\n const [elapsedTime, setElapsedTime] = useState(0)\n\n useAnimationFrame((deltaTime) => {\n setElapsedTime(prev => prev + deltaTime * speed)\n }, enabled)\n\n return elapsedTime\n}\n","import type { Color } from '../types/index.js'\nimport chalk from 'chalk'\n\nconst HEX_BASE = 16\nconst DECIMAL_BASE = 10\nconst HEX_BYTE_LENGTH = 2\nconst HEX_PAD_CHARACTER = '0'\nconst MIN_RGB_COMPONENTS = 3\nconst INTERPOLATION_MIDPOINT = 0.5\n\nconst HEX_COLOR_REGEX = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i\nconst RGB_NUMBERS_REGEX = /\\d+/g\n\nfunction rgbToHex(red: number, green: number, blue: number): string {\n const redHex = red.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const greenHex = green.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const blueHex = blue.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n return `#${redHex}${greenHex}${blueHex}`\n}\n\n/**\n * Converts a hex color string to RGB values\n *\n * @param hex - Hex color string (with or without #)\n * @returns Tuple of [red, green, blue] values (0-255) or null if invalid\n */\nexport function hexToRgb(hex: string): [number, number, number] | null {\n const result = HEX_COLOR_REGEX.exec(hex)\n if (!result)\n return null\n\n const [, redHex, greenHex, blueHex] = result\n if (!redHex || !greenHex || !blueHex)\n return null\n\n return [\n Number.parseInt(redHex, HEX_BASE),\n Number.parseInt(greenHex, HEX_BASE),\n Number.parseInt(blueHex, HEX_BASE),\n ]\n}\n\n/**\n * Applies color to text using chalk\n *\n * @param text - Text to colorize\n * @param color - Color as hex (#ff0000), rgb(255,0,0), or named color (red, blue, etc)\n * @returns Colorized text with ANSI escape codes\n */\nexport function colorize(text: string, color: Color): string {\n try {\n if (color.startsWith('#'))\n return chalk.hex(color)(text)\n\n if (color.startsWith('rgb')) {\n const match = color.match(RGB_NUMBERS_REGEX)\n if (!match || match.length < MIN_RGB_COMPONENTS)\n return text\n\n const [redStr, greenStr, blueStr] = match\n if (!redStr || !greenStr || !blueStr)\n return text\n\n const red = Number.parseInt(redStr, DECIMAL_BASE)\n const green = Number.parseInt(greenStr, DECIMAL_BASE)\n const blue = Number.parseInt(blueStr, DECIMAL_BASE)\n\n if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue))\n return text\n\n return chalk.rgb(red, green, blue)(text)\n }\n\n const chalkColor = (chalk as any)[color]\n if (typeof chalkColor === 'function')\n return chalkColor(text)\n\n return text\n }\n catch {\n return text\n }\n}\n\n/**\n * Applies opacity to a hex color by darkening it\n * Note: Terminal approximation - true opacity not possible in most terminals\n *\n * @param color - Hex color string\n * @param opacity - Opacity value from 0 (transparent/black) to 1 (fully opaque)\n * @returns Adjusted hex color or original color if not hex format\n */\nexport function applyOpacity(color: Color, opacity: number): Color {\n if (!color.startsWith('#'))\n return color\n\n const rgb = hexToRgb(color)\n if (!rgb)\n return color\n\n const [red, green, blue] = rgb\n const adjustedRed = Math.round(red * opacity)\n const adjustedGreen = Math.round(green * opacity)\n const adjustedBlue = Math.round(blue * opacity)\n\n return rgbToHex(adjustedRed, adjustedGreen, adjustedBlue)\n}\n\n/**\n * Interpolates between two colors\n *\n * @param color1 - Starting color\n * @param color2 - Ending color\n * @param progress - Interpolation progress from 0 to 1\n * @returns Interpolated color (hex if both inputs are hex, otherwise snaps to nearest)\n */\nexport function interpolateColor(\n color1: Color,\n color2: Color,\n progress: number,\n): Color {\n const isColor1Hex = color1.startsWith('#')\n const isColor2Hex = color2.startsWith('#')\n\n if (!isColor1Hex || !isColor2Hex)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const rgb1 = hexToRgb(color1)\n const rgb2 = hexToRgb(color2)\n\n if (!rgb1 || !rgb2)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const [red1, green1, blue1] = rgb1\n const [red2, green2, blue2] = rgb2\n\n const red = Math.round(red1 + (red2 - red1) * progress)\n const green = Math.round(green1 + (green2 - green1) * progress)\n const blue = Math.round(blue1 + (blue2 - blue1) * progress)\n\n return rgbToHex(red, green, blue)\n}\n","import type { EasingFunction, EasingName } from '../types/index.js'\n\nexport const linear: EasingFunction = time => time\n\nexport const easeIn: EasingFunction = time => time * time\n\nexport const easeOut: EasingFunction = time => time * (2 - time)\n\nexport const easeInOut: EasingFunction = (time) => {\n return time < 0.5\n ? 2 * time * time\n : -1 + (4 - 2 * time) * time\n}\n\nexport const sineIn: EasingFunction = time => 1 - Math.cos((time * Math.PI) / 2)\n\nexport const sineOut: EasingFunction = time => Math.sin((time * Math.PI) / 2)\n\nexport const sineInOut: EasingFunction = time => -(Math.cos(Math.PI * time) - 1) / 2\n\nexport const easingFunctions: Record<EasingName, EasingFunction> = {\n 'linear': linear,\n 'ease-in': easeIn,\n 'ease-out': easeOut,\n 'ease-in-out': easeInOut,\n 'sine-in': sineIn,\n 'sine-out': sineOut,\n 'sine-in-out': sineInOut,\n}\n\nexport function getEasingFunction(name: EasingName = 'linear'): EasingFunction {\n return easingFunctions[name]\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n return clamp((value - min) / (max - min), 0, 1)\n}\n\nexport function lerp(start: number, end: number, progress: number): number {\n return start + (end - start) * progress\n}\n","import type { BaseEffectProps, Color, EasingName } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { getEasingFunction } from '../utils/easing.js'\n\ninterface FadeProps extends BaseEffectProps {\n /**\n * Text color\n * @default '#ffffff'\n * @example 'yellow'\n */\n color?: Color\n\n /**\n * Starting opacity (0-1)\n * @default 0\n */\n from?: number\n\n /**\n * Ending opacity (0-1)\n * @default 1\n */\n to?: number\n\n /**\n * Duration in milliseconds\n * @default 1000\n */\n duration?: number\n\n /**\n * Easing function\n * @default 'ease-out'\n */\n easing?: EasingName\n\n /**\n * Loop animation continuously\n * @default false\n */\n loop?: boolean\n}\n\nconst DEFAULT_FROM = 0\nconst DEFAULT_TO = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_EASING: EasingName = 'sine-in-out'\nconst DEFAULT_LOOP = false\nconst DEFAULT_SPEED = 1\n\nfunction calculateOpacity(\n elapsedTime: number,\n duration: number,\n from: number,\n to: number,\n easing: EasingName,\n): number {\n const progress = Math.min(elapsedTime / duration, 1)\n const easedProgress = getEasingFunction(easing)(progress)\n return from + (to - from) * easedProgress\n}\n\n/**\n * Fade effect component that smoothly transitions text opacity\n *\n * Animates text from one opacity to another using configurable easing functions.\n * Can loop continuously or run once.\n *\n * Note: Optimized for dark terminals. Fades to/from black which appears as true\n * transparency on dark backgrounds. On light terminals, low opacity text may appear\n * visible as dark text. For best results on all terminals, use bright colors.\n *\n * @example\n * ```tsx\n * <Fade color=\"yellow\" from={0} to={1} duration={500} easing=\"ease-in\">\n * Success!\n * </Fade>\n * ```\n */\nexport function Fade({\n children,\n color,\n from = DEFAULT_FROM,\n to = DEFAULT_TO,\n duration = DEFAULT_DURATION_MS,\n easing = DEFAULT_EASING,\n loop = DEFAULT_LOOP,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: FadeProps) {\n const [hasCompleted, setHasCompleted] = useState(false)\n const elapsedTime = useElapsedTime(enabled && !hasCompleted, speed)\n\n useEffect(() => {\n if (!enabled)\n return\n\n const isComplete = elapsedTime >= duration\n\n if (isComplete && !loop && !hasCompleted) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: prevents calling onComplete multiple times by setting completion flag once\n setHasCompleted(true)\n onComplete?.()\n }\n }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete])\n\n const fadedText = useMemo(() => {\n let effectiveTime = elapsedTime\n if (loop) {\n const cycleTime = elapsedTime % (duration * 2)\n effectiveTime = cycleTime > duration ? (duration * 2) - cycleTime : cycleTime\n }\n else {\n effectiveTime = Math.min(elapsedTime, duration)\n }\n\n const opacity = calculateOpacity(effectiveTime, duration, from, to, easing)\n\n if (opacity < 0.01) {\n return ''\n }\n\n const baseColor = color ?? '#ffffff'\n const elegantOpacity = opacity ** 1.5\n const fadedColor = interpolateColor('#000000', baseColor, elegantOpacity)\n\n return colorize(children, fadedColor)\n }, [children, elapsedTime, duration, from, to, easing, color, loop])\n\n return <Text>{fadedText}</Text>\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\n\ninterface FlashProps extends BaseEffectProps {\n /**\n * Base color\n * @default '#ffffff'\n * @example 'cyan'\n */\n color?: Color\n\n /**\n * Minimum brightness (0-1)\n * @default 0.3\n */\n minIntensity?: number\n\n /**\n * Maximum brightness (0-1)\n * @default 1\n */\n maxIntensity?: number\n\n /**\n * Flash cycle duration in milliseconds\n * @default 1000\n */\n duration?: number\n}\n\nconst DEFAULT_COLOR = '#ffffff'\nconst DEFAULT_MIN_INTENSITY = 0.3\nconst DEFAULT_MAX_INTENSITY = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\nfunction calculateFlashIntensity(\n time: number,\n duration: number,\n minIntensity: number,\n maxIntensity: number,\n): number {\n const clampedMin = clamp(minIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const clampedMax = clamp(maxIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const normalizedTime = time / duration\n const phase = normalizedTime * FULL_CIRCLE_RADIANS\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const intensityRange = clampedMax - clampedMin\n return clampedMin + normalizedSine * intensityRange\n}\n\n/**\n * Flash effect component that creates a pulsing neon-like glow\n *\n * Animates text with a continuous brightness pulse that oscillates\n * between minimum and maximum intensity levels, creating a flashing\n * or glowing neon effect.\n *\n * @example\n * ```tsx\n * <Flash color=\"cyan\" minIntensity={0.3} maxIntensity={1} duration={800}>\n * ⥠NEON GLOW âĄ\n * </Flash>\n * ```\n */\nexport function Flash({\n children,\n color = DEFAULT_COLOR,\n minIntensity = DEFAULT_MIN_INTENSITY,\n maxIntensity = DEFAULT_MAX_INTENSITY,\n duration = DEFAULT_DURATION_MS,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: FlashProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const cycleTime = elapsedTime % duration\n\n const flashText = useMemo(() => {\n const intensity = calculateFlashIntensity(cycleTime, duration, minIntensity, maxIntensity)\n const adjustedColor = applyOpacity(color, intensity)\n return colorize(children, adjustedColor)\n }, [children, cycleTime, duration, minIntensity, maxIntensity, color])\n\n return <Text>{flashText}</Text>\n}\n","export function splitChars(text: string): string[] {\n return [...text]\n}\n\nexport function getTextLength(text: string): number {\n return [...text].length\n}\n\nexport function mapChars(\n text: string,\n fn: (char: string, index: number) => string,\n): string {\n return splitChars(text).map(fn).join('')\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo, useState } from 'react'\nimport { useAnimationFrame } from '../hooks/useAnimationFrame.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { getTextLength, mapChars } from '../utils/text.js'\n\ntype ShimmerDirection = 'left' | 'right'\n\ninterface ShimmerProps extends BaseEffectProps {\n /**\n * Gradient colours for the shimmer effect [start, peak, end]\n * @default ['#666666', '#ffffff', '#666666']\n * @example ['#60a5fa', '#3b82f6', '#60a5fa']\n */\n colors?: [Color, Color, Color]\n\n /**\n * Width of the shimmer band in characters\n * @default 4\n */\n width?: number\n\n /**\n * Brightness multiplier (0-1)\n * @default 1\n */\n intensity?: number\n\n /**\n * Direction of shimmer movement\n * @default 'right'\n */\n direction?: ShimmerDirection\n}\n\nconst DEFAULT_COLORS: [Color, Color, Color] = ['#666666', '#ffffff', '#666666']\nconst DEFAULT_WIDTH = 4\nconst DEFAULT_INTENSITY = 1\nconst DEFAULT_DIRECTION: ShimmerDirection = 'right'\nconst DEFAULT_SPEED = 1\nconst ANIMATION_CYCLE_MS = 2000\nconst COLOUR_TRANSITION_MIDPOINT = 0.5\nconst COLOUR_PROGRESS_MULTIPLIER = 2\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\n/**\n * Shimmer effect component that creates a moving highlight across text\n *\n * Creates a shimmering animation by interpolating through a gradient of colours\n * that sweeps across the text from left to right or right to left.\n *\n * @example\n * ```tsx\n * <Shimmer colors={['#60a5fa', '#3b82f6', '#60a5fa']} intensity={0.8}>\n * Loading...\n * </Shimmer>\n * ```\n */\nexport function Shimmer({\n children,\n colors = DEFAULT_COLORS,\n width = DEFAULT_WIDTH,\n intensity = DEFAULT_INTENSITY,\n direction = DEFAULT_DIRECTION,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: ShimmerProps) {\n const [offset, setOffset] = useState(0)\n const textLength = getTextLength(children)\n const totalWidth = textLength + width\n\n useAnimationFrame((deltaTime) => {\n setOffset((previousOffset) => {\n const movement = (deltaTime / ANIMATION_CYCLE_MS) * speed * totalWidth\n const newOffset = direction === 'right'\n ? previousOffset + movement\n : previousOffset - movement\n\n const hasCompletedCycle = Math.abs(newOffset) >= totalWidth\n if (hasCompletedCycle) {\n onComplete?.()\n return 0\n }\n\n return newOffset\n })\n }, enabled)\n\n const shimmerText = useMemo(() => {\n return mapChars(children, (char, index) => {\n const normalizedOffset = direction === 'right' ? offset : totalWidth - offset\n const distance = Math.abs(index - normalizedOffset)\n\n const isWithinShimmerWidth = distance < width\n const colorProgress = isWithinShimmerWidth\n ? distance / width\n : 1\n\n const [startColor, peakColor, endColor] = colors\n const adjustedIntensity = clamp(intensity, MIN_INTENSITY, MAX_INTENSITY)\n\n const isFirstHalf = colorProgress < COLOUR_TRANSITION_MIDPOINT\n const currentColor = isFirstHalf\n ? interpolateColor(\n startColor,\n peakColor,\n colorProgress * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n : interpolateColor(\n peakColor,\n endColor,\n (colorProgress - COLOUR_TRANSITION_MIDPOINT) * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n\n return colorize(char, currentColor)\n })\n }, [children, offset, colors, width, intensity, direction, totalWidth])\n\n return <Text>{shimmerText}</Text>\n}\n","import { useEffect, useRef, useState } from 'react'\n\nconst CURSOR_BLINK_INTERVAL_MS = 500\n\ninterface UseCursorBlinkOptions {\n enabled: boolean\n isComplete: boolean\n}\n\n/**\n * Hook that manages cursor blinking state\n *\n * @param options - Configuration for cursor blink\n * @param options.enabled - Whether cursor blinking is enabled\n * @param options.isComplete - Whether typing is complete\n * @returns Whether cursor should be visible\n */\nexport function useCursorBlink({\n enabled,\n isComplete,\n}: UseCursorBlinkOptions): boolean {\n const [showCursor, setShowCursor] = useState(true)\n const intervalRef = useRef<Timer>()\n\n useEffect(() => {\n if (!enabled || isComplete) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: synchronizing cursor visibility with prop changes\n setShowCursor(false)\n return\n }\n\n intervalRef.current = setInterval(() => {\n setShowCursor(previous => !previous)\n }, CURSOR_BLINK_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current)\n clearInterval(intervalRef.current)\n }\n }, [enabled, isComplete])\n\n return showCursor\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { clamp } from '../utils/easing.js'\n\nconst BASE_CHARACTER_DELAY_MS = 80\nconst MIN_VARIANCE = 0\nconst MAX_VARIANCE = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction calculateCharacterDelay(\n speed: number,\n variance: number,\n): number {\n const clampedVariance = clamp(variance, MIN_VARIANCE, MAX_VARIANCE)\n const randomVariance = (Math.random() - 0.5) * clampedVariance\n return (BASE_CHARACTER_DELAY_MS / speed) * (1 + randomVariance)\n}\n\ninterface UseTypewriterProgressOptions {\n totalCharacters: number\n speed: number\n variance: number\n initialDelay: number\n enabled: boolean\n onComplete?: () => void\n}\n\n/**\n * Hook that manages typewriter character reveal timing\n *\n * @param options - Configuration for typewriter progress\n * @param options.totalCharacters - Total number of characters to reveal\n * @param options.speed - Animation speed multiplier\n * @param options.variance - Typing variance for human-like timing (0-1)\n * @param options.initialDelay - Delay before typing starts in milliseconds\n * @param options.enabled - Whether the animation is enabled\n * @param options.onComplete - Callback when typing completes\n * @returns Number of characters to display\n */\nexport function useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay,\n enabled,\n onComplete,\n}: UseTypewriterProgressOptions): number {\n const [visibleCharacters, setVisibleCharacters] = useState(0)\n const timeoutRef = useRef<Timer>()\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n\n useEffect(() => {\n if (!enabled)\n return\n\n if (hasCompletedTyping) {\n onComplete?.()\n return\n }\n\n const characterDelay = calculateCharacterDelay(speed, variance)\n const isFirstCharacter = visibleCharacters === FIRST_CHARACTER_INDEX\n const totalDelay = isFirstCharacter ? initialDelay + characterDelay : characterDelay\n\n timeoutRef.current = setTimeout(() => {\n setVisibleCharacters(previous => previous + 1)\n }, totalDelay)\n\n return () => {\n if (timeoutRef.current)\n clearTimeout(timeoutRef.current)\n }\n }, [visibleCharacters, enabled, speed, variance, initialDelay, hasCompletedTyping, onComplete])\n\n return visibleCharacters\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useCursorBlink } from '../hooks/useCursorBlink.js'\nimport { useTypewriterProgress } from '../hooks/useTypewriterProgress.js'\nimport { colorize } from '../utils/colors.js'\nimport { getTextLength, splitChars } from '../utils/text.js'\n\ninterface TypewriterProps extends BaseEffectProps {\n /**\n * Text color\n * @default undefined (inherits)\n * @example 'green'\n */\n color?: Color\n\n /**\n * Cursor character or false to disable\n * @default 'â'\n * @example 'â'\n */\n cursor?: string | boolean\n\n /**\n * Cursor color (defaults to text color)\n * @default undefined\n * @example 'cyan'\n */\n cursorColor?: Color\n\n /**\n * Typing speed randomness (0-1) for more human-like typing\n * @default 0.3\n */\n variance?: number\n\n /**\n * Initial delay before typing starts (ms)\n * @default 0\n */\n delay?: number\n}\n\nconst DEFAULT_CURSOR = 'â'\nconst DEFAULT_VARIANCE = 0.3\nconst DEFAULT_DELAY = 0\nconst DEFAULT_SPEED = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction getCursorCharacter(cursor: string | boolean): string {\n return typeof cursor === 'string' ? cursor : DEFAULT_CURSOR\n}\n\nfunction formatCursor(\n cursorCharacter: string,\n cursorColor: Color | undefined,\n textColor: Color | undefined,\n): string {\n if (cursorColor)\n return colorize(cursorCharacter, cursorColor)\n\n if (textColor)\n return colorize(cursorCharacter, textColor)\n\n return cursorCharacter\n}\n\n/**\n * Typewriter effect component that reveals text character by character\n *\n * Simulates typing text with configurable speed, variance for realistic timing,\n * and an optional cursor. The cursor blinks while typing is in progress.\n *\n * @example\n * ```tsx\n * <Typewriter color=\"green\" cursor=\"â\" variance={0.5} speed={2}>\n * npm install ink-motion\n * </Typewriter>\n * ```\n */\nexport function Typewriter({\n children,\n color,\n cursor = DEFAULT_CURSOR,\n cursorColor,\n variance = DEFAULT_VARIANCE,\n delay = DEFAULT_DELAY,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: TypewriterProps) {\n const characters = splitChars(children)\n const totalCharacters = getTextLength(children)\n\n const visibleCharacters = useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay: delay,\n enabled,\n onComplete,\n })\n\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n const isCursorEnabled = cursor !== false\n\n const showCursor = useCursorBlink({\n enabled: enabled && isCursorEnabled,\n isComplete: hasCompletedTyping,\n })\n\n const displayText = useMemo(() => {\n const visibleText = characters.slice(FIRST_CHARACTER_INDEX, visibleCharacters).join('')\n const coloredText = color ? colorize(visibleText, color) : visibleText\n\n const shouldShowCursor = isCursorEnabled && showCursor && !hasCompletedTyping\n if (!shouldShowCursor)\n return coloredText\n\n const cursorCharacter = getCursorCharacter(cursor)\n const cursorText = formatCursor(cursorCharacter, cursorColor, color)\n\n return coloredText + cursorText\n }, [characters, visibleCharacters, color, cursor, cursorColor, showCursor, hasCompletedTyping, isCursorEnabled])\n\n return <Text>{displayText}</Text>\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { mapChars } from '../utils/text.js'\n\ntype WaveType = 'brightness' | 'vertical'\n\ninterface WaveProps extends BaseEffectProps {\n /**\n * Gradient colors for the wave [dark, bright]\n * @default ['#888888', '#ffffff']\n * @example ['#ec4899', '#8b5cf6']\n */\n colors?: [Color, Color]\n\n /**\n * Wave height (0-1)\n * @default 0.5\n */\n amplitude?: number\n\n /**\n * Number of wave cycles across text\n * @default 2\n */\n frequency?: number\n\n /**\n * Wave effect type\n * @default 'brightness'\n */\n type?: WaveType\n}\n\nconst DEFAULT_COLORS: [Color, Color] = ['#888888', '#ffffff']\nconst DEFAULT_AMPLITUDE = 0.5\nconst DEFAULT_FREQUENCY = 2\nconst DEFAULT_TYPE: WaveType = 'brightness'\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst WAVE_PERIOD_MS = 2000\nconst MIN_AMPLITUDE = 0\nconst MAX_AMPLITUDE = 1\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst VERTICAL_SHIFT_THRESHOLD = 0.5\n\nfunction calculateWaveValue(\n characterIndex: number,\n time: number,\n frequency: number,\n amplitude: number,\n): number {\n const clampedAmplitude = clamp(amplitude, MIN_AMPLITUDE, MAX_AMPLITUDE)\n const safeFrequency = frequency || DEFAULT_FREQUENCY\n const waveLength = FULL_CIRCLE_RADIANS / safeFrequency\n const spatialComponent = (characterIndex / waveLength) * FULL_CIRCLE_RADIANS\n const temporalComponent = time * FULL_CIRCLE_RADIANS\n const phase = spatialComponent - temporalComponent\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const amplitudeComplement = MAX_AMPLITUDE - clampedAmplitude\n return normalizedSine * clampedAmplitude + amplitudeComplement\n}\n\n/**\n * Wave effect component that creates a wave motion through text\n *\n * Animates text with a sine wave pattern that can affect brightness or vertical position.\n * The wave continuously flows through the text.\n *\n * @example\n * ```tsx\n * <Wave colors={['#ec4899', '#8b5cf6']} amplitude={0.7} frequency={3}>\n * ~~ wavy text ~~\n * </Wave>\n * ```\n */\nexport function Wave({\n children,\n colors = DEFAULT_COLORS,\n amplitude = DEFAULT_AMPLITUDE,\n frequency = DEFAULT_FREQUENCY,\n type = DEFAULT_TYPE,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: WaveProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const normalizedTime = elapsedTime / WAVE_PERIOD_MS\n\n const waveText = useMemo(() => {\n if (type === 'brightness') {\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const [darkColor, brightColor] = colors\n const characterColor = interpolateColor(darkColor, brightColor, waveValue)\n return colorize(character, characterColor)\n })\n }\n\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const shouldShift = waveValue > VERTICAL_SHIFT_THRESHOLD\n return shouldShift ? ` ${character}` : character\n })\n }, [children, normalizedTime, colors, amplitude, frequency, type])\n\n return <Text>{waveText}</Text>\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* Note: Props use 'color' (US spelling) for React convention, but type uses UK spelling
|
|
4
|
+
* Color value as hex (#ff0000), rgb (rgb(255,0,0)), or named (red, blue, etc.)
|
|
6
5
|
*/
|
|
7
|
-
type
|
|
8
|
-
/**
|
|
9
|
-
* @deprecated Use Colour instead
|
|
10
|
-
*/
|
|
11
|
-
type Color = Colour;
|
|
6
|
+
type Color = string;
|
|
12
7
|
/**
|
|
13
8
|
* Easing function that takes normalised time (0-1) and returns eased value (0-1)
|
|
14
9
|
*/
|
|
@@ -16,7 +11,7 @@ type EasingFunction = (time: number) => number;
|
|
|
16
11
|
/**
|
|
17
12
|
* Named easing functions
|
|
18
13
|
*/
|
|
19
|
-
type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
|
|
14
|
+
type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'sine-in' | 'sine-out' | 'sine-in-out';
|
|
20
15
|
/**
|
|
21
16
|
* Base props shared by all effect components
|
|
22
17
|
*/
|
|
@@ -45,11 +40,11 @@ interface BaseEffectProps {
|
|
|
45
40
|
|
|
46
41
|
interface FadeProps extends BaseEffectProps {
|
|
47
42
|
/**
|
|
48
|
-
* Text
|
|
43
|
+
* Text color
|
|
49
44
|
* @default '#ffffff'
|
|
50
45
|
* @example 'yellow'
|
|
51
46
|
*/
|
|
52
|
-
color?:
|
|
47
|
+
color?: Color;
|
|
53
48
|
/**
|
|
54
49
|
* Starting opacity (0-1)
|
|
55
50
|
* @default 0
|
|
@@ -82,6 +77,10 @@ interface FadeProps extends BaseEffectProps {
|
|
|
82
77
|
* Animates text from one opacity to another using configurable easing functions.
|
|
83
78
|
* Can loop continuously or run once.
|
|
84
79
|
*
|
|
80
|
+
* Note: Optimized for dark terminals. Fades to/from black which appears as true
|
|
81
|
+
* transparency on dark backgrounds. On light terminals, low opacity text may appear
|
|
82
|
+
* visible as dark text. For best results on all terminals, use bright colors.
|
|
83
|
+
*
|
|
85
84
|
* @example
|
|
86
85
|
* ```tsx
|
|
87
86
|
* <Fade color="yellow" from={0} to={1} duration={500} easing="ease-in">
|
|
@@ -93,11 +92,11 @@ declare function Fade({ children, color, from, to, duration, easing, loop, speed
|
|
|
93
92
|
|
|
94
93
|
interface FlashProps extends BaseEffectProps {
|
|
95
94
|
/**
|
|
96
|
-
*
|
|
95
|
+
* Base color
|
|
97
96
|
* @default '#ffffff'
|
|
98
97
|
* @example 'cyan'
|
|
99
98
|
*/
|
|
100
|
-
color?:
|
|
99
|
+
color?: Color;
|
|
101
100
|
/**
|
|
102
101
|
* Minimum brightness (0-1)
|
|
103
102
|
* @default 0.3
|
|
@@ -137,7 +136,7 @@ interface ShimmerProps extends BaseEffectProps {
|
|
|
137
136
|
* @default ['#666666', '#ffffff', '#666666']
|
|
138
137
|
* @example ['#60a5fa', '#3b82f6', '#60a5fa']
|
|
139
138
|
*/
|
|
140
|
-
colors?: [
|
|
139
|
+
colors?: [Color, Color, Color];
|
|
141
140
|
/**
|
|
142
141
|
* Width of the shimmer band in characters
|
|
143
142
|
* @default 4
|
|
@@ -171,11 +170,11 @@ declare function Shimmer({ children, colors, width, intensity, direction, speed,
|
|
|
171
170
|
|
|
172
171
|
interface TypewriterProps extends BaseEffectProps {
|
|
173
172
|
/**
|
|
174
|
-
* Text
|
|
173
|
+
* Text color
|
|
175
174
|
* @default undefined (inherits)
|
|
176
175
|
* @example 'green'
|
|
177
176
|
*/
|
|
178
|
-
color?:
|
|
177
|
+
color?: Color;
|
|
179
178
|
/**
|
|
180
179
|
* Cursor character or false to disable
|
|
181
180
|
* @default 'â'
|
|
@@ -183,11 +182,11 @@ interface TypewriterProps extends BaseEffectProps {
|
|
|
183
182
|
*/
|
|
184
183
|
cursor?: string | boolean;
|
|
185
184
|
/**
|
|
186
|
-
* Cursor
|
|
185
|
+
* Cursor color (defaults to text color)
|
|
187
186
|
* @default undefined
|
|
188
187
|
* @example 'cyan'
|
|
189
188
|
*/
|
|
190
|
-
cursorColor?:
|
|
189
|
+
cursorColor?: Color;
|
|
191
190
|
/**
|
|
192
191
|
* Typing speed randomness (0-1) for more human-like typing
|
|
193
192
|
* @default 0.3
|
|
@@ -217,11 +216,11 @@ declare function Typewriter({ children, color, cursor, cursorColor, variance, de
|
|
|
217
216
|
type WaveType = 'brightness' | 'vertical';
|
|
218
217
|
interface WaveProps extends BaseEffectProps {
|
|
219
218
|
/**
|
|
220
|
-
* Gradient
|
|
219
|
+
* Gradient colors for the wave [dark, bright]
|
|
221
220
|
* @default ['#888888', '#ffffff']
|
|
222
221
|
* @example ['#ec4899', '#8b5cf6']
|
|
223
222
|
*/
|
|
224
|
-
colors?: [
|
|
223
|
+
colors?: [Color, Color];
|
|
225
224
|
/**
|
|
226
225
|
* Wave height (0-1)
|
|
227
226
|
* @default 0.5
|
|
@@ -306,4 +305,4 @@ interface UseTypewriterProgressOptions {
|
|
|
306
305
|
*/
|
|
307
306
|
declare function useTypewriterProgress({ totalCharacters, speed, variance, initialDelay, enabled, onComplete, }: UseTypewriterProgressOptions): number;
|
|
308
307
|
|
|
309
|
-
export { type BaseEffectProps, type Color, type
|
|
308
|
+
export { type BaseEffectProps, type Color, type EasingFunction, type EasingName, Fade, Flash, Shimmer, Typewriter, Wave, useAnimationFrame, useCursorBlink, useElapsedTime, useTypewriterProgress };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* Note: Props use 'color' (US spelling) for React convention, but type uses UK spelling
|
|
4
|
+
* Color value as hex (#ff0000), rgb (rgb(255,0,0)), or named (red, blue, etc.)
|
|
6
5
|
*/
|
|
7
|
-
type
|
|
8
|
-
/**
|
|
9
|
-
* @deprecated Use Colour instead
|
|
10
|
-
*/
|
|
11
|
-
type Color = Colour;
|
|
6
|
+
type Color = string;
|
|
12
7
|
/**
|
|
13
8
|
* Easing function that takes normalised time (0-1) and returns eased value (0-1)
|
|
14
9
|
*/
|
|
@@ -16,7 +11,7 @@ type EasingFunction = (time: number) => number;
|
|
|
16
11
|
/**
|
|
17
12
|
* Named easing functions
|
|
18
13
|
*/
|
|
19
|
-
type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
|
|
14
|
+
type EasingName = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'sine-in' | 'sine-out' | 'sine-in-out';
|
|
20
15
|
/**
|
|
21
16
|
* Base props shared by all effect components
|
|
22
17
|
*/
|
|
@@ -45,11 +40,11 @@ interface BaseEffectProps {
|
|
|
45
40
|
|
|
46
41
|
interface FadeProps extends BaseEffectProps {
|
|
47
42
|
/**
|
|
48
|
-
* Text
|
|
43
|
+
* Text color
|
|
49
44
|
* @default '#ffffff'
|
|
50
45
|
* @example 'yellow'
|
|
51
46
|
*/
|
|
52
|
-
color?:
|
|
47
|
+
color?: Color;
|
|
53
48
|
/**
|
|
54
49
|
* Starting opacity (0-1)
|
|
55
50
|
* @default 0
|
|
@@ -82,6 +77,10 @@ interface FadeProps extends BaseEffectProps {
|
|
|
82
77
|
* Animates text from one opacity to another using configurable easing functions.
|
|
83
78
|
* Can loop continuously or run once.
|
|
84
79
|
*
|
|
80
|
+
* Note: Optimized for dark terminals. Fades to/from black which appears as true
|
|
81
|
+
* transparency on dark backgrounds. On light terminals, low opacity text may appear
|
|
82
|
+
* visible as dark text. For best results on all terminals, use bright colors.
|
|
83
|
+
*
|
|
85
84
|
* @example
|
|
86
85
|
* ```tsx
|
|
87
86
|
* <Fade color="yellow" from={0} to={1} duration={500} easing="ease-in">
|
|
@@ -93,11 +92,11 @@ declare function Fade({ children, color, from, to, duration, easing, loop, speed
|
|
|
93
92
|
|
|
94
93
|
interface FlashProps extends BaseEffectProps {
|
|
95
94
|
/**
|
|
96
|
-
*
|
|
95
|
+
* Base color
|
|
97
96
|
* @default '#ffffff'
|
|
98
97
|
* @example 'cyan'
|
|
99
98
|
*/
|
|
100
|
-
color?:
|
|
99
|
+
color?: Color;
|
|
101
100
|
/**
|
|
102
101
|
* Minimum brightness (0-1)
|
|
103
102
|
* @default 0.3
|
|
@@ -137,7 +136,7 @@ interface ShimmerProps extends BaseEffectProps {
|
|
|
137
136
|
* @default ['#666666', '#ffffff', '#666666']
|
|
138
137
|
* @example ['#60a5fa', '#3b82f6', '#60a5fa']
|
|
139
138
|
*/
|
|
140
|
-
colors?: [
|
|
139
|
+
colors?: [Color, Color, Color];
|
|
141
140
|
/**
|
|
142
141
|
* Width of the shimmer band in characters
|
|
143
142
|
* @default 4
|
|
@@ -171,11 +170,11 @@ declare function Shimmer({ children, colors, width, intensity, direction, speed,
|
|
|
171
170
|
|
|
172
171
|
interface TypewriterProps extends BaseEffectProps {
|
|
173
172
|
/**
|
|
174
|
-
* Text
|
|
173
|
+
* Text color
|
|
175
174
|
* @default undefined (inherits)
|
|
176
175
|
* @example 'green'
|
|
177
176
|
*/
|
|
178
|
-
color?:
|
|
177
|
+
color?: Color;
|
|
179
178
|
/**
|
|
180
179
|
* Cursor character or false to disable
|
|
181
180
|
* @default 'â'
|
|
@@ -183,11 +182,11 @@ interface TypewriterProps extends BaseEffectProps {
|
|
|
183
182
|
*/
|
|
184
183
|
cursor?: string | boolean;
|
|
185
184
|
/**
|
|
186
|
-
* Cursor
|
|
185
|
+
* Cursor color (defaults to text color)
|
|
187
186
|
* @default undefined
|
|
188
187
|
* @example 'cyan'
|
|
189
188
|
*/
|
|
190
|
-
cursorColor?:
|
|
189
|
+
cursorColor?: Color;
|
|
191
190
|
/**
|
|
192
191
|
* Typing speed randomness (0-1) for more human-like typing
|
|
193
192
|
* @default 0.3
|
|
@@ -217,11 +216,11 @@ declare function Typewriter({ children, color, cursor, cursorColor, variance, de
|
|
|
217
216
|
type WaveType = 'brightness' | 'vertical';
|
|
218
217
|
interface WaveProps extends BaseEffectProps {
|
|
219
218
|
/**
|
|
220
|
-
* Gradient
|
|
219
|
+
* Gradient colors for the wave [dark, bright]
|
|
221
220
|
* @default ['#888888', '#ffffff']
|
|
222
221
|
* @example ['#ec4899', '#8b5cf6']
|
|
223
222
|
*/
|
|
224
|
-
colors?: [
|
|
223
|
+
colors?: [Color, Color];
|
|
225
224
|
/**
|
|
226
225
|
* Wave height (0-1)
|
|
227
226
|
* @default 0.5
|
|
@@ -306,4 +305,4 @@ interface UseTypewriterProgressOptions {
|
|
|
306
305
|
*/
|
|
307
306
|
declare function useTypewriterProgress({ totalCharacters, speed, variance, initialDelay, enabled, onComplete, }: UseTypewriterProgressOptions): number;
|
|
308
307
|
|
|
309
|
-
export { type BaseEffectProps, type Color, type
|
|
308
|
+
export { type BaseEffectProps, type Color, type EasingFunction, type EasingName, Fade, Flash, Shimmer, Typewriter, Wave, useAnimationFrame, useCursorBlink, useElapsedTime, useTypewriterProgress };
|
package/dist/index.js
CHANGED
|
@@ -64,6 +64,8 @@ function hexToRgb(hex) {
|
|
|
64
64
|
if (!result)
|
|
65
65
|
return null;
|
|
66
66
|
const [, redHex, greenHex, blueHex] = result;
|
|
67
|
+
if (!redHex || !greenHex || !blueHex)
|
|
68
|
+
return null;
|
|
67
69
|
return [
|
|
68
70
|
Number.parseInt(redHex, HEX_BASE),
|
|
69
71
|
Number.parseInt(greenHex, HEX_BASE),
|
|
@@ -79,6 +81,8 @@ function colorize(text, color) {
|
|
|
79
81
|
if (!match || match.length < MIN_RGB_COMPONENTS)
|
|
80
82
|
return text;
|
|
81
83
|
const [redStr, greenStr, blueStr] = match;
|
|
84
|
+
if (!redStr || !greenStr || !blueStr)
|
|
85
|
+
return text;
|
|
82
86
|
const red = Number.parseInt(redStr, DECIMAL_BASE);
|
|
83
87
|
const green = Number.parseInt(greenStr, DECIMAL_BASE);
|
|
84
88
|
const blue = Number.parseInt(blueStr, DECIMAL_BASE);
|
|
@@ -130,11 +134,17 @@ var easeOut = (time) => time * (2 - time);
|
|
|
130
134
|
var easeInOut = (time) => {
|
|
131
135
|
return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time;
|
|
132
136
|
};
|
|
137
|
+
var sineIn = (time) => 1 - Math.cos(time * Math.PI / 2);
|
|
138
|
+
var sineOut = (time) => Math.sin(time * Math.PI / 2);
|
|
139
|
+
var sineInOut = (time) => -(Math.cos(Math.PI * time) - 1) / 2;
|
|
133
140
|
var easingFunctions = {
|
|
134
141
|
"linear": linear,
|
|
135
142
|
"ease-in": easeIn,
|
|
136
143
|
"ease-out": easeOut,
|
|
137
|
-
"ease-in-out": easeInOut
|
|
144
|
+
"ease-in-out": easeInOut,
|
|
145
|
+
"sine-in": sineIn,
|
|
146
|
+
"sine-out": sineOut,
|
|
147
|
+
"sine-in-out": sineInOut
|
|
138
148
|
};
|
|
139
149
|
function getEasingFunction(name = "linear") {
|
|
140
150
|
return easingFunctions[name];
|
|
@@ -145,7 +155,7 @@ function clamp(value, min, max) {
|
|
|
145
155
|
var DEFAULT_FROM = 0;
|
|
146
156
|
var DEFAULT_TO = 1;
|
|
147
157
|
var DEFAULT_DURATION_MS = 1e3;
|
|
148
|
-
var DEFAULT_EASING = "
|
|
158
|
+
var DEFAULT_EASING = "sine-in-out";
|
|
149
159
|
var DEFAULT_LOOP = false;
|
|
150
160
|
var DEFAULT_SPEED = 1;
|
|
151
161
|
function calculateOpacity(elapsedTime, duration, from, to, easing) {
|
|
@@ -177,10 +187,20 @@ function Fade({
|
|
|
177
187
|
}
|
|
178
188
|
}, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete]);
|
|
179
189
|
const fadedText = useMemo(() => {
|
|
180
|
-
|
|
190
|
+
let effectiveTime = elapsedTime;
|
|
191
|
+
if (loop) {
|
|
192
|
+
const cycleTime = elapsedTime % (duration * 2);
|
|
193
|
+
effectiveTime = cycleTime > duration ? duration * 2 - cycleTime : cycleTime;
|
|
194
|
+
} else {
|
|
195
|
+
effectiveTime = Math.min(elapsedTime, duration);
|
|
196
|
+
}
|
|
181
197
|
const opacity = calculateOpacity(effectiveTime, duration, from, to, easing);
|
|
198
|
+
if (opacity < 0.01) {
|
|
199
|
+
return "";
|
|
200
|
+
}
|
|
182
201
|
const baseColor = color ?? "#ffffff";
|
|
183
|
-
const
|
|
202
|
+
const elegantOpacity = opacity ** 1.5;
|
|
203
|
+
const fadedColor = interpolateColor("#000000", baseColor, elegantOpacity);
|
|
184
204
|
return colorize(children, fadedColor);
|
|
185
205
|
}, [children, elapsedTime, duration, from, to, easing, color, loop]);
|
|
186
206
|
return /* @__PURE__ */ jsx(Text, { children: fadedText });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useAnimationFrame.ts","../src/hooks/useElapsedTime.ts","../src/utils/colors.ts","../src/utils/easing.ts","../src/components/Fade.tsx","../src/components/Flash.tsx","../src/utils/text.ts","../src/components/Shimmer.tsx","../src/hooks/useCursorBlink.ts","../src/hooks/useTypewriterProgress.ts","../src/components/Typewriter.tsx","../src/components/Wave.tsx"],"names":["useState","useEffect","DEFAULT_DURATION_MS","DEFAULT_SPEED","useMemo","jsx","Text","MIN_INTENSITY","MAX_INTENSITY","useRef","FIRST_CHARACTER_INDEX","DEFAULT_COLORS","FULL_CIRCLE_RADIANS","SINE_WAVE_OFFSET","SINE_WAVE_NORMALIZE"],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, useRef } from 'react'\n\nconst TARGET_FPS = 60\nconst FRAME_INTERVAL_MS = 1000 / TARGET_FPS\n\n/**\n * Runs a callback on every animation frame using setInterval\n *\n * @param callback - Function called each frame with delta time in ms\n * @param enabled - Whether animation is active\n */\nexport function useAnimationFrame(\n callback: (deltaTime: number) => void,\n enabled: boolean = true,\n): void {\n const intervalRef = useRef<Timer>()\n const previousTimeRef = useRef<number>()\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n previousTimeRef.current = undefined\n return\n }\n\n intervalRef.current = setInterval(() => {\n const currentTime = Date.now()\n if (previousTimeRef.current !== undefined) {\n const deltaTime = currentTime - previousTimeRef.current\n callbackRef.current(deltaTime)\n }\n previousTimeRef.current = currentTime\n }, FRAME_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [enabled])\n}\n","import { useState } from 'react'\nimport { useAnimationFrame } from './useAnimationFrame.js'\n\n/**\n * Hook that tracks elapsed time since mount or last reset\n *\n * @param enabled - Whether to track time\n * @param speed - Speed multiplier (default: 1)\n * @returns Elapsed time in milliseconds\n */\nexport function useElapsedTime(\n enabled: boolean = true,\n speed: number = 1,\n): number {\n const [elapsedTime, setElapsedTime] = useState(0)\n\n useAnimationFrame((deltaTime) => {\n setElapsedTime(prev => prev + deltaTime * speed)\n }, enabled)\n\n return elapsedTime\n}\n","import type { Colour } from '../types/index.js'\nimport chalk from 'chalk'\n\nconst HEX_BASE = 16\nconst DECIMAL_BASE = 10\nconst HEX_BYTE_LENGTH = 2\nconst HEX_PAD_CHARACTER = '0'\nconst MIN_RGB_COMPONENTS = 3\nconst INTERPOLATION_MIDPOINT = 0.5\n\nconst HEX_COLOR_REGEX = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i\nconst RGB_NUMBERS_REGEX = /\\d+/g\n\nfunction rgbToHex(red: number, green: number, blue: number): string {\n const redHex = red.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const greenHex = green.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const blueHex = blue.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n return `#${redHex}${greenHex}${blueHex}`\n}\n\n/**\n * Converts a hex color string to RGB values\n *\n * @param hex - Hex color string (with or without #)\n * @returns Tuple of [red, green, blue] values (0-255) or null if invalid\n */\nexport function hexToRgb(hex: string): [number, number, number] | null {\n const result = HEX_COLOR_REGEX.exec(hex)\n if (!result)\n return null\n\n const [, redHex, greenHex, blueHex] = result\n return [\n Number.parseInt(redHex, HEX_BASE),\n Number.parseInt(greenHex, HEX_BASE),\n Number.parseInt(blueHex, HEX_BASE),\n ]\n}\n\n/**\n * Applies color to text using chalk\n *\n * @param text - Text to colorize\n * @param color - Color as hex (#ff0000), rgb(255,0,0), or named color (red, blue, etc)\n * @returns Colorized text with ANSI escape codes\n */\nexport function colorize(text: string, color: Colour): string {\n try {\n if (color.startsWith('#'))\n return chalk.hex(color)(text)\n\n if (color.startsWith('rgb')) {\n const match = color.match(RGB_NUMBERS_REGEX)\n if (!match || match.length < MIN_RGB_COMPONENTS)\n return text\n\n const [redStr, greenStr, blueStr] = match\n const red = Number.parseInt(redStr, DECIMAL_BASE)\n const green = Number.parseInt(greenStr, DECIMAL_BASE)\n const blue = Number.parseInt(blueStr, DECIMAL_BASE)\n\n if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue))\n return text\n\n return chalk.rgb(red, green, blue)(text)\n }\n\n const chalkColor = chalk[color as keyof typeof chalk]\n if (typeof chalkColor === 'function')\n return chalkColor(text)\n\n return text\n }\n catch {\n return text\n }\n}\n\n/**\n * Applies opacity to a hex color by darkening it\n * Note: Terminal approximation - true opacity not possible in most terminals\n *\n * @param color - Hex color string\n * @param opacity - Opacity value from 0 (transparent/black) to 1 (fully opaque)\n * @returns Adjusted hex color or original color if not hex format\n */\nexport function applyOpacity(color: Colour, opacity: number): Colour {\n if (!color.startsWith('#'))\n return color\n\n const rgb = hexToRgb(color)\n if (!rgb)\n return color\n\n const [red, green, blue] = rgb\n const adjustedRed = Math.round(red * opacity)\n const adjustedGreen = Math.round(green * opacity)\n const adjustedBlue = Math.round(blue * opacity)\n\n return rgbToHex(adjustedRed, adjustedGreen, adjustedBlue)\n}\n\n/**\n * Interpolates between two colors\n *\n * @param color1 - Starting color\n * @param color2 - Ending color\n * @param progress - Interpolation progress from 0 to 1\n * @returns Interpolated color (hex if both inputs are hex, otherwise snaps to nearest)\n */\nexport function interpolateColor(\n color1: Colour,\n color2: Colour,\n progress: number,\n): Colour {\n const isColor1Hex = color1.startsWith('#')\n const isColor2Hex = color2.startsWith('#')\n\n if (!isColor1Hex || !isColor2Hex)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const rgb1 = hexToRgb(color1)\n const rgb2 = hexToRgb(color2)\n\n if (!rgb1 || !rgb2)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const [red1, green1, blue1] = rgb1\n const [red2, green2, blue2] = rgb2\n\n const red = Math.round(red1 + (red2 - red1) * progress)\n const green = Math.round(green1 + (green2 - green1) * progress)\n const blue = Math.round(blue1 + (blue2 - blue1) * progress)\n\n return rgbToHex(red, green, blue)\n}\n","import type { EasingFunction, EasingName } from '../types/index.js'\n\nexport const linear: EasingFunction = time => time\n\nexport const easeIn: EasingFunction = time => time * time\n\nexport const easeOut: EasingFunction = time => time * (2 - time)\n\nexport const easeInOut: EasingFunction = (time) => {\n return time < 0.5\n ? 2 * time * time\n : -1 + (4 - 2 * time) * time\n}\n\nexport const easingFunctions: Record<EasingName, EasingFunction> = {\n 'linear': linear,\n 'ease-in': easeIn,\n 'ease-out': easeOut,\n 'ease-in-out': easeInOut,\n}\n\nexport function getEasingFunction(name: EasingName = 'linear'): EasingFunction {\n return easingFunctions[name]\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n return clamp((value - min) / (max - min), 0, 1)\n}\n\nexport function lerp(start: number, end: number, progress: number): number {\n return start + (end - start) * progress\n}\n","import type { BaseEffectProps, Colour, EasingName } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { getEasingFunction } from '../utils/easing.js'\n\ninterface FadeProps extends BaseEffectProps {\n /**\n * Text colour\n * @default '#ffffff'\n * @example 'yellow'\n */\n color?: Colour\n\n /**\n * Starting opacity (0-1)\n * @default 0\n */\n from?: number\n\n /**\n * Ending opacity (0-1)\n * @default 1\n */\n to?: number\n\n /**\n * Duration in milliseconds\n * @default 1000\n */\n duration?: number\n\n /**\n * Easing function\n * @default 'ease-out'\n */\n easing?: EasingName\n\n /**\n * Loop animation continuously\n * @default false\n */\n loop?: boolean\n}\n\nconst DEFAULT_FROM = 0\nconst DEFAULT_TO = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_EASING: EasingName = 'ease-out'\nconst DEFAULT_LOOP = false\nconst DEFAULT_SPEED = 1\n\nfunction calculateOpacity(\n elapsedTime: number,\n duration: number,\n from: number,\n to: number,\n easing: EasingName,\n): number {\n const progress = Math.min(elapsedTime / duration, 1)\n const easedProgress = getEasingFunction(easing)(progress)\n return from + (to - from) * easedProgress\n}\n\n/**\n * Fade effect component that smoothly transitions text opacity\n *\n * Animates text from one opacity to another using configurable easing functions.\n * Can loop continuously or run once.\n *\n * @example\n * ```tsx\n * <Fade color=\"yellow\" from={0} to={1} duration={500} easing=\"ease-in\">\n * Success!\n * </Fade>\n * ```\n */\nexport function Fade({\n children,\n color,\n from = DEFAULT_FROM,\n to = DEFAULT_TO,\n duration = DEFAULT_DURATION_MS,\n easing = DEFAULT_EASING,\n loop = DEFAULT_LOOP,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: FadeProps) {\n const [hasCompleted, setHasCompleted] = useState(false)\n const elapsedTime = useElapsedTime(enabled && !hasCompleted, speed)\n\n useEffect(() => {\n if (!enabled)\n return\n\n const isComplete = elapsedTime >= duration\n\n if (isComplete && !loop && !hasCompleted) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: prevents calling onComplete multiple times by setting completion flag once\n setHasCompleted(true)\n onComplete?.()\n }\n }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete])\n\n const fadedText = useMemo(() => {\n const effectiveTime = loop ? elapsedTime % duration : Math.min(elapsedTime, duration)\n const opacity = calculateOpacity(effectiveTime, duration, from, to, easing)\n\n const baseColor = color ?? '#ffffff'\n const fadedColor = applyOpacity(baseColor, opacity)\n\n return colorize(children, fadedColor)\n }, [children, elapsedTime, duration, from, to, easing, color, loop])\n\n return <Text>{fadedText}</Text>\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\n\ninterface FlashProps extends BaseEffectProps {\n /**\n * Text colour\n * @default '#ffffff'\n * @example 'cyan'\n */\n color?: Colour\n\n /**\n * Minimum brightness (0-1)\n * @default 0.3\n */\n minIntensity?: number\n\n /**\n * Maximum brightness (0-1)\n * @default 1\n */\n maxIntensity?: number\n\n /**\n * Flash cycle duration in milliseconds\n * @default 1000\n */\n duration?: number\n}\n\nconst DEFAULT_COLOR = '#ffffff'\nconst DEFAULT_MIN_INTENSITY = 0.3\nconst DEFAULT_MAX_INTENSITY = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\nfunction calculateFlashIntensity(\n time: number,\n duration: number,\n minIntensity: number,\n maxIntensity: number,\n): number {\n const clampedMin = clamp(minIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const clampedMax = clamp(maxIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const normalizedTime = time / duration\n const phase = normalizedTime * FULL_CIRCLE_RADIANS\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const intensityRange = clampedMax - clampedMin\n return clampedMin + normalizedSine * intensityRange\n}\n\n/**\n * Flash effect component that creates a pulsing neon-like glow\n *\n * Animates text with a continuous brightness pulse that oscillates\n * between minimum and maximum intensity levels, creating a flashing\n * or glowing neon effect.\n *\n * @example\n * ```tsx\n * <Flash color=\"cyan\" minIntensity={0.3} maxIntensity={1} duration={800}>\n * ⥠NEON GLOW âĄ\n * </Flash>\n * ```\n */\nexport function Flash({\n children,\n color = DEFAULT_COLOR,\n minIntensity = DEFAULT_MIN_INTENSITY,\n maxIntensity = DEFAULT_MAX_INTENSITY,\n duration = DEFAULT_DURATION_MS,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: FlashProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const cycleTime = elapsedTime % duration\n\n const flashText = useMemo(() => {\n const intensity = calculateFlashIntensity(cycleTime, duration, minIntensity, maxIntensity)\n const adjustedColor = applyOpacity(color, intensity)\n return colorize(children, adjustedColor)\n }, [children, cycleTime, duration, minIntensity, maxIntensity, color])\n\n return <Text>{flashText}</Text>\n}\n","export function splitChars(text: string): string[] {\n return [...text]\n}\n\nexport function getTextLength(text: string): number {\n return [...text].length\n}\n\nexport function mapChars(\n text: string,\n fn: (char: string, index: number) => string,\n): string {\n return splitChars(text).map(fn).join('')\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo, useState } from 'react'\nimport { useAnimationFrame } from '../hooks/useAnimationFrame.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { getTextLength, mapChars } from '../utils/text.js'\n\ntype ShimmerDirection = 'left' | 'right'\n\ninterface ShimmerProps extends BaseEffectProps {\n /**\n * Gradient colours for the shimmer effect [start, peak, end]\n * @default ['#666666', '#ffffff', '#666666']\n * @example ['#60a5fa', '#3b82f6', '#60a5fa']\n */\n colors?: [Colour, Colour, Colour]\n\n /**\n * Width of the shimmer band in characters\n * @default 4\n */\n width?: number\n\n /**\n * Brightness multiplier (0-1)\n * @default 1\n */\n intensity?: number\n\n /**\n * Direction of shimmer movement\n * @default 'right'\n */\n direction?: ShimmerDirection\n}\n\nconst DEFAULT_COLORS: [Colour, Colour, Colour] = ['#666666', '#ffffff', '#666666']\nconst DEFAULT_WIDTH = 4\nconst DEFAULT_INTENSITY = 1\nconst DEFAULT_DIRECTION: ShimmerDirection = 'right'\nconst DEFAULT_SPEED = 1\nconst ANIMATION_CYCLE_MS = 2000\nconst COLOUR_TRANSITION_MIDPOINT = 0.5\nconst COLOUR_PROGRESS_MULTIPLIER = 2\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\n/**\n * Shimmer effect component that creates a moving highlight across text\n *\n * Creates a shimmering animation by interpolating through a gradient of colours\n * that sweeps across the text from left to right or right to left.\n *\n * @example\n * ```tsx\n * <Shimmer colors={['#60a5fa', '#3b82f6', '#60a5fa']} intensity={0.8}>\n * Loading...\n * </Shimmer>\n * ```\n */\nexport function Shimmer({\n children,\n colors = DEFAULT_COLORS,\n width = DEFAULT_WIDTH,\n intensity = DEFAULT_INTENSITY,\n direction = DEFAULT_DIRECTION,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: ShimmerProps) {\n const [offset, setOffset] = useState(0)\n const textLength = getTextLength(children)\n const totalWidth = textLength + width\n\n useAnimationFrame((deltaTime) => {\n setOffset((previousOffset) => {\n const movement = (deltaTime / ANIMATION_CYCLE_MS) * speed * totalWidth\n const newOffset = direction === 'right'\n ? previousOffset + movement\n : previousOffset - movement\n\n const hasCompletedCycle = Math.abs(newOffset) >= totalWidth\n if (hasCompletedCycle) {\n onComplete?.()\n return 0\n }\n\n return newOffset\n })\n }, enabled)\n\n const shimmerText = useMemo(() => {\n return mapChars(children, (char, index) => {\n const normalizedOffset = direction === 'right' ? offset : totalWidth - offset\n const distance = Math.abs(index - normalizedOffset)\n\n const isWithinShimmerWidth = distance < width\n const colorProgress = isWithinShimmerWidth\n ? distance / width\n : 1\n\n const [startColor, peakColor, endColor] = colors\n const adjustedIntensity = clamp(intensity, MIN_INTENSITY, MAX_INTENSITY)\n\n const isFirstHalf = colorProgress < COLOUR_TRANSITION_MIDPOINT\n const currentColor = isFirstHalf\n ? interpolateColor(\n startColor,\n peakColor,\n colorProgress * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n : interpolateColor(\n peakColor,\n endColor,\n (colorProgress - COLOUR_TRANSITION_MIDPOINT) * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n\n return colorize(char, currentColor)\n })\n }, [children, offset, colors, width, intensity, direction, totalWidth])\n\n return <Text>{shimmerText}</Text>\n}\n","import { useEffect, useRef, useState } from 'react'\n\nconst CURSOR_BLINK_INTERVAL_MS = 500\n\ninterface UseCursorBlinkOptions {\n enabled: boolean\n isComplete: boolean\n}\n\n/**\n * Hook that manages cursor blinking state\n *\n * @param options - Configuration for cursor blink\n * @param options.enabled - Whether cursor blinking is enabled\n * @param options.isComplete - Whether typing is complete\n * @returns Whether cursor should be visible\n */\nexport function useCursorBlink({\n enabled,\n isComplete,\n}: UseCursorBlinkOptions): boolean {\n const [showCursor, setShowCursor] = useState(true)\n const intervalRef = useRef<Timer>()\n\n useEffect(() => {\n if (!enabled || isComplete) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: synchronizing cursor visibility with prop changes\n setShowCursor(false)\n return\n }\n\n intervalRef.current = setInterval(() => {\n setShowCursor(previous => !previous)\n }, CURSOR_BLINK_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current)\n clearInterval(intervalRef.current)\n }\n }, [enabled, isComplete])\n\n return showCursor\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { clamp } from '../utils/easing.js'\n\nconst BASE_CHARACTER_DELAY_MS = 80\nconst MIN_VARIANCE = 0\nconst MAX_VARIANCE = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction calculateCharacterDelay(\n speed: number,\n variance: number,\n): number {\n const clampedVariance = clamp(variance, MIN_VARIANCE, MAX_VARIANCE)\n const randomVariance = (Math.random() - 0.5) * clampedVariance\n return (BASE_CHARACTER_DELAY_MS / speed) * (1 + randomVariance)\n}\n\ninterface UseTypewriterProgressOptions {\n totalCharacters: number\n speed: number\n variance: number\n initialDelay: number\n enabled: boolean\n onComplete?: () => void\n}\n\n/**\n * Hook that manages typewriter character reveal timing\n *\n * @param options - Configuration for typewriter progress\n * @param options.totalCharacters - Total number of characters to reveal\n * @param options.speed - Animation speed multiplier\n * @param options.variance - Typing variance for human-like timing (0-1)\n * @param options.initialDelay - Delay before typing starts in milliseconds\n * @param options.enabled - Whether the animation is enabled\n * @param options.onComplete - Callback when typing completes\n * @returns Number of characters to display\n */\nexport function useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay,\n enabled,\n onComplete,\n}: UseTypewriterProgressOptions): number {\n const [visibleCharacters, setVisibleCharacters] = useState(0)\n const timeoutRef = useRef<Timer>()\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n\n useEffect(() => {\n if (!enabled)\n return\n\n if (hasCompletedTyping) {\n onComplete?.()\n return\n }\n\n const characterDelay = calculateCharacterDelay(speed, variance)\n const isFirstCharacter = visibleCharacters === FIRST_CHARACTER_INDEX\n const totalDelay = isFirstCharacter ? initialDelay + characterDelay : characterDelay\n\n timeoutRef.current = setTimeout(() => {\n setVisibleCharacters(previous => previous + 1)\n }, totalDelay)\n\n return () => {\n if (timeoutRef.current)\n clearTimeout(timeoutRef.current)\n }\n }, [visibleCharacters, enabled, speed, variance, initialDelay, hasCompletedTyping, onComplete])\n\n return visibleCharacters\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useCursorBlink } from '../hooks/useCursorBlink.js'\nimport { useTypewriterProgress } from '../hooks/useTypewriterProgress.js'\nimport { colorize } from '../utils/colors.js'\nimport { getTextLength, splitChars } from '../utils/text.js'\n\ninterface TypewriterProps extends BaseEffectProps {\n /**\n * Text colour\n * @default undefined (inherits)\n * @example 'green'\n */\n color?: Colour\n\n /**\n * Cursor character or false to disable\n * @default 'â'\n * @example 'â'\n */\n cursor?: string | boolean\n\n /**\n * Cursor colour (defaults to text colour)\n * @default undefined\n * @example 'cyan'\n */\n cursorColor?: Colour\n\n /**\n * Typing speed randomness (0-1) for more human-like typing\n * @default 0.3\n */\n variance?: number\n\n /**\n * Initial delay before typing starts (ms)\n * @default 0\n */\n delay?: number\n}\n\nconst DEFAULT_CURSOR = 'â'\nconst DEFAULT_VARIANCE = 0.3\nconst DEFAULT_DELAY = 0\nconst DEFAULT_SPEED = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction getCursorCharacter(cursor: string | boolean): string {\n return typeof cursor === 'string' ? cursor : DEFAULT_CURSOR\n}\n\nfunction formatCursor(\n cursorCharacter: string,\n cursorColor: Colour | undefined,\n textColor: Colour | undefined,\n): string {\n if (cursorColor)\n return colorize(cursorCharacter, cursorColor)\n\n if (textColor)\n return colorize(cursorCharacter, textColor)\n\n return cursorCharacter\n}\n\n/**\n * Typewriter effect component that reveals text character by character\n *\n * Simulates typing text with configurable speed, variance for realistic timing,\n * and an optional cursor. The cursor blinks while typing is in progress.\n *\n * @example\n * ```tsx\n * <Typewriter color=\"green\" cursor=\"â\" variance={0.5} speed={2}>\n * npm install ink-motion\n * </Typewriter>\n * ```\n */\nexport function Typewriter({\n children,\n color,\n cursor = DEFAULT_CURSOR,\n cursorColor,\n variance = DEFAULT_VARIANCE,\n delay = DEFAULT_DELAY,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: TypewriterProps) {\n const characters = splitChars(children)\n const totalCharacters = getTextLength(children)\n\n const visibleCharacters = useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay: delay,\n enabled,\n onComplete,\n })\n\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n const isCursorEnabled = cursor !== false\n\n const showCursor = useCursorBlink({\n enabled: enabled && isCursorEnabled,\n isComplete: hasCompletedTyping,\n })\n\n const displayText = useMemo(() => {\n const visibleText = characters.slice(FIRST_CHARACTER_INDEX, visibleCharacters).join('')\n const coloredText = color ? colorize(visibleText, color) : visibleText\n\n const shouldShowCursor = isCursorEnabled && showCursor && !hasCompletedTyping\n if (!shouldShowCursor)\n return coloredText\n\n const cursorCharacter = getCursorCharacter(cursor)\n const cursorText = formatCursor(cursorCharacter, cursorColor, color)\n\n return coloredText + cursorText\n }, [characters, visibleCharacters, color, cursor, cursorColor, showCursor, hasCompletedTyping, isCursorEnabled])\n\n return <Text>{displayText}</Text>\n}\n","import type { BaseEffectProps, Colour } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { mapChars } from '../utils/text.js'\n\ntype WaveType = 'brightness' | 'vertical'\n\ninterface WaveProps extends BaseEffectProps {\n /**\n * Gradient colours for the wave [dark, bright]\n * @default ['#888888', '#ffffff']\n * @example ['#ec4899', '#8b5cf6']\n */\n colors?: [Colour, Colour]\n\n /**\n * Wave height (0-1)\n * @default 0.5\n */\n amplitude?: number\n\n /**\n * Number of wave cycles across text\n * @default 2\n */\n frequency?: number\n\n /**\n * Wave effect type\n * @default 'brightness'\n */\n type?: WaveType\n}\n\nconst DEFAULT_COLORS: [Colour, Colour] = ['#888888', '#ffffff']\nconst DEFAULT_AMPLITUDE = 0.5\nconst DEFAULT_FREQUENCY = 2\nconst DEFAULT_TYPE: WaveType = 'brightness'\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst WAVE_PERIOD_MS = 2000\nconst MIN_AMPLITUDE = 0\nconst MAX_AMPLITUDE = 1\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst VERTICAL_SHIFT_THRESHOLD = 0.5\n\nfunction calculateWaveValue(\n characterIndex: number,\n time: number,\n frequency: number,\n amplitude: number,\n): number {\n const clampedAmplitude = clamp(amplitude, MIN_AMPLITUDE, MAX_AMPLITUDE)\n const safeFrequency = frequency || DEFAULT_FREQUENCY\n const waveLength = FULL_CIRCLE_RADIANS / safeFrequency\n const spatialComponent = (characterIndex / waveLength) * FULL_CIRCLE_RADIANS\n const temporalComponent = time * FULL_CIRCLE_RADIANS\n const phase = spatialComponent - temporalComponent\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const amplitudeComplement = MAX_AMPLITUDE - clampedAmplitude\n return normalizedSine * clampedAmplitude + amplitudeComplement\n}\n\n/**\n * Wave effect component that creates a wave motion through text\n *\n * Animates text with a sine wave pattern that can affect brightness or vertical position.\n * The wave continuously flows through the text.\n *\n * @example\n * ```tsx\n * <Wave colors={['#ec4899', '#8b5cf6']} amplitude={0.7} frequency={3}>\n * ~~ wavy text ~~\n * </Wave>\n * ```\n */\nexport function Wave({\n children,\n colors = DEFAULT_COLORS,\n amplitude = DEFAULT_AMPLITUDE,\n frequency = DEFAULT_FREQUENCY,\n type = DEFAULT_TYPE,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: WaveProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const normalizedTime = elapsedTime / WAVE_PERIOD_MS\n\n const waveText = useMemo(() => {\n if (type === 'brightness') {\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const [darkColor, brightColor] = colors\n const characterColor = interpolateColor(darkColor, brightColor, waveValue)\n return colorize(character, characterColor)\n })\n }\n\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const shouldShift = waveValue > VERTICAL_SHIFT_THRESHOLD\n return shouldShift ? ` ${character}` : character\n })\n }, [children, normalizedTime, colors, amplitude, frequency, type])\n\n return <Text>{waveText}</Text>\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useAnimationFrame.ts","../src/hooks/useElapsedTime.ts","../src/utils/colors.ts","../src/utils/easing.ts","../src/components/Fade.tsx","../src/components/Flash.tsx","../src/utils/text.ts","../src/components/Shimmer.tsx","../src/hooks/useCursorBlink.ts","../src/hooks/useTypewriterProgress.ts","../src/components/Typewriter.tsx","../src/components/Wave.tsx"],"names":["useState","useEffect","DEFAULT_DURATION_MS","DEFAULT_SPEED","useMemo","jsx","Text","MIN_INTENSITY","MAX_INTENSITY","useRef","FIRST_CHARACTER_INDEX","DEFAULT_COLORS","FULL_CIRCLE_RADIANS","SINE_WAVE_OFFSET","SINE_WAVE_NORMALIZE"],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, useRef } from 'react'\n\nconst TARGET_FPS = 60\nconst FRAME_INTERVAL_MS = 1000 / TARGET_FPS\n\n/**\n * Runs a callback on every animation frame using setInterval\n *\n * @param callback - Function called each frame with delta time in ms\n * @param enabled - Whether animation is active\n */\nexport function useAnimationFrame(\n callback: (deltaTime: number) => void,\n enabled: boolean = true,\n): void {\n const intervalRef = useRef<Timer>()\n const previousTimeRef = useRef<number>()\n const callbackRef = useRef(callback)\n\n useEffect(() => {\n callbackRef.current = callback\n }, [callback])\n\n useEffect(() => {\n if (!enabled) {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n previousTimeRef.current = undefined\n return\n }\n\n intervalRef.current = setInterval(() => {\n const currentTime = Date.now()\n if (previousTimeRef.current !== undefined) {\n const deltaTime = currentTime - previousTimeRef.current\n callbackRef.current(deltaTime)\n }\n previousTimeRef.current = currentTime\n }, FRAME_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [enabled])\n}\n","import { useState } from 'react'\nimport { useAnimationFrame } from './useAnimationFrame.js'\n\n/**\n * Hook that tracks elapsed time since mount or last reset\n *\n * @param enabled - Whether to track time\n * @param speed - Speed multiplier (default: 1)\n * @returns Elapsed time in milliseconds\n */\nexport function useElapsedTime(\n enabled: boolean = true,\n speed: number = 1,\n): number {\n const [elapsedTime, setElapsedTime] = useState(0)\n\n useAnimationFrame((deltaTime) => {\n setElapsedTime(prev => prev + deltaTime * speed)\n }, enabled)\n\n return elapsedTime\n}\n","import type { Color } from '../types/index.js'\nimport chalk from 'chalk'\n\nconst HEX_BASE = 16\nconst DECIMAL_BASE = 10\nconst HEX_BYTE_LENGTH = 2\nconst HEX_PAD_CHARACTER = '0'\nconst MIN_RGB_COMPONENTS = 3\nconst INTERPOLATION_MIDPOINT = 0.5\n\nconst HEX_COLOR_REGEX = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i\nconst RGB_NUMBERS_REGEX = /\\d+/g\n\nfunction rgbToHex(red: number, green: number, blue: number): string {\n const redHex = red.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const greenHex = green.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n const blueHex = blue.toString(HEX_BASE).padStart(HEX_BYTE_LENGTH, HEX_PAD_CHARACTER)\n return `#${redHex}${greenHex}${blueHex}`\n}\n\n/**\n * Converts a hex color string to RGB values\n *\n * @param hex - Hex color string (with or without #)\n * @returns Tuple of [red, green, blue] values (0-255) or null if invalid\n */\nexport function hexToRgb(hex: string): [number, number, number] | null {\n const result = HEX_COLOR_REGEX.exec(hex)\n if (!result)\n return null\n\n const [, redHex, greenHex, blueHex] = result\n if (!redHex || !greenHex || !blueHex)\n return null\n\n return [\n Number.parseInt(redHex, HEX_BASE),\n Number.parseInt(greenHex, HEX_BASE),\n Number.parseInt(blueHex, HEX_BASE),\n ]\n}\n\n/**\n * Applies color to text using chalk\n *\n * @param text - Text to colorize\n * @param color - Color as hex (#ff0000), rgb(255,0,0), or named color (red, blue, etc)\n * @returns Colorized text with ANSI escape codes\n */\nexport function colorize(text: string, color: Color): string {\n try {\n if (color.startsWith('#'))\n return chalk.hex(color)(text)\n\n if (color.startsWith('rgb')) {\n const match = color.match(RGB_NUMBERS_REGEX)\n if (!match || match.length < MIN_RGB_COMPONENTS)\n return text\n\n const [redStr, greenStr, blueStr] = match\n if (!redStr || !greenStr || !blueStr)\n return text\n\n const red = Number.parseInt(redStr, DECIMAL_BASE)\n const green = Number.parseInt(greenStr, DECIMAL_BASE)\n const blue = Number.parseInt(blueStr, DECIMAL_BASE)\n\n if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue))\n return text\n\n return chalk.rgb(red, green, blue)(text)\n }\n\n const chalkColor = (chalk as any)[color]\n if (typeof chalkColor === 'function')\n return chalkColor(text)\n\n return text\n }\n catch {\n return text\n }\n}\n\n/**\n * Applies opacity to a hex color by darkening it\n * Note: Terminal approximation - true opacity not possible in most terminals\n *\n * @param color - Hex color string\n * @param opacity - Opacity value from 0 (transparent/black) to 1 (fully opaque)\n * @returns Adjusted hex color or original color if not hex format\n */\nexport function applyOpacity(color: Color, opacity: number): Color {\n if (!color.startsWith('#'))\n return color\n\n const rgb = hexToRgb(color)\n if (!rgb)\n return color\n\n const [red, green, blue] = rgb\n const adjustedRed = Math.round(red * opacity)\n const adjustedGreen = Math.round(green * opacity)\n const adjustedBlue = Math.round(blue * opacity)\n\n return rgbToHex(adjustedRed, adjustedGreen, adjustedBlue)\n}\n\n/**\n * Interpolates between two colors\n *\n * @param color1 - Starting color\n * @param color2 - Ending color\n * @param progress - Interpolation progress from 0 to 1\n * @returns Interpolated color (hex if both inputs are hex, otherwise snaps to nearest)\n */\nexport function interpolateColor(\n color1: Color,\n color2: Color,\n progress: number,\n): Color {\n const isColor1Hex = color1.startsWith('#')\n const isColor2Hex = color2.startsWith('#')\n\n if (!isColor1Hex || !isColor2Hex)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const rgb1 = hexToRgb(color1)\n const rgb2 = hexToRgb(color2)\n\n if (!rgb1 || !rgb2)\n return progress < INTERPOLATION_MIDPOINT ? color1 : color2\n\n const [red1, green1, blue1] = rgb1\n const [red2, green2, blue2] = rgb2\n\n const red = Math.round(red1 + (red2 - red1) * progress)\n const green = Math.round(green1 + (green2 - green1) * progress)\n const blue = Math.round(blue1 + (blue2 - blue1) * progress)\n\n return rgbToHex(red, green, blue)\n}\n","import type { EasingFunction, EasingName } from '../types/index.js'\n\nexport const linear: EasingFunction = time => time\n\nexport const easeIn: EasingFunction = time => time * time\n\nexport const easeOut: EasingFunction = time => time * (2 - time)\n\nexport const easeInOut: EasingFunction = (time) => {\n return time < 0.5\n ? 2 * time * time\n : -1 + (4 - 2 * time) * time\n}\n\nexport const sineIn: EasingFunction = time => 1 - Math.cos((time * Math.PI) / 2)\n\nexport const sineOut: EasingFunction = time => Math.sin((time * Math.PI) / 2)\n\nexport const sineInOut: EasingFunction = time => -(Math.cos(Math.PI * time) - 1) / 2\n\nexport const easingFunctions: Record<EasingName, EasingFunction> = {\n 'linear': linear,\n 'ease-in': easeIn,\n 'ease-out': easeOut,\n 'ease-in-out': easeInOut,\n 'sine-in': sineIn,\n 'sine-out': sineOut,\n 'sine-in-out': sineInOut,\n}\n\nexport function getEasingFunction(name: EasingName = 'linear'): EasingFunction {\n return easingFunctions[name]\n}\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n return clamp((value - min) / (max - min), 0, 1)\n}\n\nexport function lerp(start: number, end: number, progress: number): number {\n return start + (end - start) * progress\n}\n","import type { BaseEffectProps, Color, EasingName } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { getEasingFunction } from '../utils/easing.js'\n\ninterface FadeProps extends BaseEffectProps {\n /**\n * Text color\n * @default '#ffffff'\n * @example 'yellow'\n */\n color?: Color\n\n /**\n * Starting opacity (0-1)\n * @default 0\n */\n from?: number\n\n /**\n * Ending opacity (0-1)\n * @default 1\n */\n to?: number\n\n /**\n * Duration in milliseconds\n * @default 1000\n */\n duration?: number\n\n /**\n * Easing function\n * @default 'ease-out'\n */\n easing?: EasingName\n\n /**\n * Loop animation continuously\n * @default false\n */\n loop?: boolean\n}\n\nconst DEFAULT_FROM = 0\nconst DEFAULT_TO = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_EASING: EasingName = 'sine-in-out'\nconst DEFAULT_LOOP = false\nconst DEFAULT_SPEED = 1\n\nfunction calculateOpacity(\n elapsedTime: number,\n duration: number,\n from: number,\n to: number,\n easing: EasingName,\n): number {\n const progress = Math.min(elapsedTime / duration, 1)\n const easedProgress = getEasingFunction(easing)(progress)\n return from + (to - from) * easedProgress\n}\n\n/**\n * Fade effect component that smoothly transitions text opacity\n *\n * Animates text from one opacity to another using configurable easing functions.\n * Can loop continuously or run once.\n *\n * Note: Optimized for dark terminals. Fades to/from black which appears as true\n * transparency on dark backgrounds. On light terminals, low opacity text may appear\n * visible as dark text. For best results on all terminals, use bright colors.\n *\n * @example\n * ```tsx\n * <Fade color=\"yellow\" from={0} to={1} duration={500} easing=\"ease-in\">\n * Success!\n * </Fade>\n * ```\n */\nexport function Fade({\n children,\n color,\n from = DEFAULT_FROM,\n to = DEFAULT_TO,\n duration = DEFAULT_DURATION_MS,\n easing = DEFAULT_EASING,\n loop = DEFAULT_LOOP,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: FadeProps) {\n const [hasCompleted, setHasCompleted] = useState(false)\n const elapsedTime = useElapsedTime(enabled && !hasCompleted, speed)\n\n useEffect(() => {\n if (!enabled)\n return\n\n const isComplete = elapsedTime >= duration\n\n if (isComplete && !loop && !hasCompleted) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: prevents calling onComplete multiple times by setting completion flag once\n setHasCompleted(true)\n onComplete?.()\n }\n }, [elapsedTime, duration, loop, hasCompleted, enabled, onComplete])\n\n const fadedText = useMemo(() => {\n let effectiveTime = elapsedTime\n if (loop) {\n const cycleTime = elapsedTime % (duration * 2)\n effectiveTime = cycleTime > duration ? (duration * 2) - cycleTime : cycleTime\n }\n else {\n effectiveTime = Math.min(elapsedTime, duration)\n }\n\n const opacity = calculateOpacity(effectiveTime, duration, from, to, easing)\n\n if (opacity < 0.01) {\n return ''\n }\n\n const baseColor = color ?? '#ffffff'\n const elegantOpacity = opacity ** 1.5\n const fadedColor = interpolateColor('#000000', baseColor, elegantOpacity)\n\n return colorize(children, fadedColor)\n }, [children, elapsedTime, duration, from, to, easing, color, loop])\n\n return <Text>{fadedText}</Text>\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { applyOpacity, colorize } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\n\ninterface FlashProps extends BaseEffectProps {\n /**\n * Base color\n * @default '#ffffff'\n * @example 'cyan'\n */\n color?: Color\n\n /**\n * Minimum brightness (0-1)\n * @default 0.3\n */\n minIntensity?: number\n\n /**\n * Maximum brightness (0-1)\n * @default 1\n */\n maxIntensity?: number\n\n /**\n * Flash cycle duration in milliseconds\n * @default 1000\n */\n duration?: number\n}\n\nconst DEFAULT_COLOR = '#ffffff'\nconst DEFAULT_MIN_INTENSITY = 0.3\nconst DEFAULT_MAX_INTENSITY = 1\nconst DEFAULT_DURATION_MS = 1000\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\nfunction calculateFlashIntensity(\n time: number,\n duration: number,\n minIntensity: number,\n maxIntensity: number,\n): number {\n const clampedMin = clamp(minIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const clampedMax = clamp(maxIntensity, MIN_INTENSITY, MAX_INTENSITY)\n const normalizedTime = time / duration\n const phase = normalizedTime * FULL_CIRCLE_RADIANS\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const intensityRange = clampedMax - clampedMin\n return clampedMin + normalizedSine * intensityRange\n}\n\n/**\n * Flash effect component that creates a pulsing neon-like glow\n *\n * Animates text with a continuous brightness pulse that oscillates\n * between minimum and maximum intensity levels, creating a flashing\n * or glowing neon effect.\n *\n * @example\n * ```tsx\n * <Flash color=\"cyan\" minIntensity={0.3} maxIntensity={1} duration={800}>\n * ⥠NEON GLOW âĄ\n * </Flash>\n * ```\n */\nexport function Flash({\n children,\n color = DEFAULT_COLOR,\n minIntensity = DEFAULT_MIN_INTENSITY,\n maxIntensity = DEFAULT_MAX_INTENSITY,\n duration = DEFAULT_DURATION_MS,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: FlashProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const cycleTime = elapsedTime % duration\n\n const flashText = useMemo(() => {\n const intensity = calculateFlashIntensity(cycleTime, duration, minIntensity, maxIntensity)\n const adjustedColor = applyOpacity(color, intensity)\n return colorize(children, adjustedColor)\n }, [children, cycleTime, duration, minIntensity, maxIntensity, color])\n\n return <Text>{flashText}</Text>\n}\n","export function splitChars(text: string): string[] {\n return [...text]\n}\n\nexport function getTextLength(text: string): number {\n return [...text].length\n}\n\nexport function mapChars(\n text: string,\n fn: (char: string, index: number) => string,\n): string {\n return splitChars(text).map(fn).join('')\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo, useState } from 'react'\nimport { useAnimationFrame } from '../hooks/useAnimationFrame.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { getTextLength, mapChars } from '../utils/text.js'\n\ntype ShimmerDirection = 'left' | 'right'\n\ninterface ShimmerProps extends BaseEffectProps {\n /**\n * Gradient colours for the shimmer effect [start, peak, end]\n * @default ['#666666', '#ffffff', '#666666']\n * @example ['#60a5fa', '#3b82f6', '#60a5fa']\n */\n colors?: [Color, Color, Color]\n\n /**\n * Width of the shimmer band in characters\n * @default 4\n */\n width?: number\n\n /**\n * Brightness multiplier (0-1)\n * @default 1\n */\n intensity?: number\n\n /**\n * Direction of shimmer movement\n * @default 'right'\n */\n direction?: ShimmerDirection\n}\n\nconst DEFAULT_COLORS: [Color, Color, Color] = ['#666666', '#ffffff', '#666666']\nconst DEFAULT_WIDTH = 4\nconst DEFAULT_INTENSITY = 1\nconst DEFAULT_DIRECTION: ShimmerDirection = 'right'\nconst DEFAULT_SPEED = 1\nconst ANIMATION_CYCLE_MS = 2000\nconst COLOUR_TRANSITION_MIDPOINT = 0.5\nconst COLOUR_PROGRESS_MULTIPLIER = 2\nconst MIN_INTENSITY = 0\nconst MAX_INTENSITY = 1\n\n/**\n * Shimmer effect component that creates a moving highlight across text\n *\n * Creates a shimmering animation by interpolating through a gradient of colours\n * that sweeps across the text from left to right or right to left.\n *\n * @example\n * ```tsx\n * <Shimmer colors={['#60a5fa', '#3b82f6', '#60a5fa']} intensity={0.8}>\n * Loading...\n * </Shimmer>\n * ```\n */\nexport function Shimmer({\n children,\n colors = DEFAULT_COLORS,\n width = DEFAULT_WIDTH,\n intensity = DEFAULT_INTENSITY,\n direction = DEFAULT_DIRECTION,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: ShimmerProps) {\n const [offset, setOffset] = useState(0)\n const textLength = getTextLength(children)\n const totalWidth = textLength + width\n\n useAnimationFrame((deltaTime) => {\n setOffset((previousOffset) => {\n const movement = (deltaTime / ANIMATION_CYCLE_MS) * speed * totalWidth\n const newOffset = direction === 'right'\n ? previousOffset + movement\n : previousOffset - movement\n\n const hasCompletedCycle = Math.abs(newOffset) >= totalWidth\n if (hasCompletedCycle) {\n onComplete?.()\n return 0\n }\n\n return newOffset\n })\n }, enabled)\n\n const shimmerText = useMemo(() => {\n return mapChars(children, (char, index) => {\n const normalizedOffset = direction === 'right' ? offset : totalWidth - offset\n const distance = Math.abs(index - normalizedOffset)\n\n const isWithinShimmerWidth = distance < width\n const colorProgress = isWithinShimmerWidth\n ? distance / width\n : 1\n\n const [startColor, peakColor, endColor] = colors\n const adjustedIntensity = clamp(intensity, MIN_INTENSITY, MAX_INTENSITY)\n\n const isFirstHalf = colorProgress < COLOUR_TRANSITION_MIDPOINT\n const currentColor = isFirstHalf\n ? interpolateColor(\n startColor,\n peakColor,\n colorProgress * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n : interpolateColor(\n peakColor,\n endColor,\n (colorProgress - COLOUR_TRANSITION_MIDPOINT) * COLOUR_PROGRESS_MULTIPLIER * adjustedIntensity,\n )\n\n return colorize(char, currentColor)\n })\n }, [children, offset, colors, width, intensity, direction, totalWidth])\n\n return <Text>{shimmerText}</Text>\n}\n","import { useEffect, useRef, useState } from 'react'\n\nconst CURSOR_BLINK_INTERVAL_MS = 500\n\ninterface UseCursorBlinkOptions {\n enabled: boolean\n isComplete: boolean\n}\n\n/**\n * Hook that manages cursor blinking state\n *\n * @param options - Configuration for cursor blink\n * @param options.enabled - Whether cursor blinking is enabled\n * @param options.isComplete - Whether typing is complete\n * @returns Whether cursor should be visible\n */\nexport function useCursorBlink({\n enabled,\n isComplete,\n}: UseCursorBlinkOptions): boolean {\n const [showCursor, setShowCursor] = useState(true)\n const intervalRef = useRef<Timer>()\n\n useEffect(() => {\n if (!enabled || isComplete) {\n // eslint-disable-next-line react-hooks-extra/no-direct-set-state-in-use-effect -- Intentional: synchronizing cursor visibility with prop changes\n setShowCursor(false)\n return\n }\n\n intervalRef.current = setInterval(() => {\n setShowCursor(previous => !previous)\n }, CURSOR_BLINK_INTERVAL_MS)\n\n return () => {\n if (intervalRef.current)\n clearInterval(intervalRef.current)\n }\n }, [enabled, isComplete])\n\n return showCursor\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { clamp } from '../utils/easing.js'\n\nconst BASE_CHARACTER_DELAY_MS = 80\nconst MIN_VARIANCE = 0\nconst MAX_VARIANCE = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction calculateCharacterDelay(\n speed: number,\n variance: number,\n): number {\n const clampedVariance = clamp(variance, MIN_VARIANCE, MAX_VARIANCE)\n const randomVariance = (Math.random() - 0.5) * clampedVariance\n return (BASE_CHARACTER_DELAY_MS / speed) * (1 + randomVariance)\n}\n\ninterface UseTypewriterProgressOptions {\n totalCharacters: number\n speed: number\n variance: number\n initialDelay: number\n enabled: boolean\n onComplete?: () => void\n}\n\n/**\n * Hook that manages typewriter character reveal timing\n *\n * @param options - Configuration for typewriter progress\n * @param options.totalCharacters - Total number of characters to reveal\n * @param options.speed - Animation speed multiplier\n * @param options.variance - Typing variance for human-like timing (0-1)\n * @param options.initialDelay - Delay before typing starts in milliseconds\n * @param options.enabled - Whether the animation is enabled\n * @param options.onComplete - Callback when typing completes\n * @returns Number of characters to display\n */\nexport function useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay,\n enabled,\n onComplete,\n}: UseTypewriterProgressOptions): number {\n const [visibleCharacters, setVisibleCharacters] = useState(0)\n const timeoutRef = useRef<Timer>()\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n\n useEffect(() => {\n if (!enabled)\n return\n\n if (hasCompletedTyping) {\n onComplete?.()\n return\n }\n\n const characterDelay = calculateCharacterDelay(speed, variance)\n const isFirstCharacter = visibleCharacters === FIRST_CHARACTER_INDEX\n const totalDelay = isFirstCharacter ? initialDelay + characterDelay : characterDelay\n\n timeoutRef.current = setTimeout(() => {\n setVisibleCharacters(previous => previous + 1)\n }, totalDelay)\n\n return () => {\n if (timeoutRef.current)\n clearTimeout(timeoutRef.current)\n }\n }, [visibleCharacters, enabled, speed, variance, initialDelay, hasCompletedTyping, onComplete])\n\n return visibleCharacters\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useCursorBlink } from '../hooks/useCursorBlink.js'\nimport { useTypewriterProgress } from '../hooks/useTypewriterProgress.js'\nimport { colorize } from '../utils/colors.js'\nimport { getTextLength, splitChars } from '../utils/text.js'\n\ninterface TypewriterProps extends BaseEffectProps {\n /**\n * Text color\n * @default undefined (inherits)\n * @example 'green'\n */\n color?: Color\n\n /**\n * Cursor character or false to disable\n * @default 'â'\n * @example 'â'\n */\n cursor?: string | boolean\n\n /**\n * Cursor color (defaults to text color)\n * @default undefined\n * @example 'cyan'\n */\n cursorColor?: Color\n\n /**\n * Typing speed randomness (0-1) for more human-like typing\n * @default 0.3\n */\n variance?: number\n\n /**\n * Initial delay before typing starts (ms)\n * @default 0\n */\n delay?: number\n}\n\nconst DEFAULT_CURSOR = 'â'\nconst DEFAULT_VARIANCE = 0.3\nconst DEFAULT_DELAY = 0\nconst DEFAULT_SPEED = 1\nconst FIRST_CHARACTER_INDEX = 0\n\nfunction getCursorCharacter(cursor: string | boolean): string {\n return typeof cursor === 'string' ? cursor : DEFAULT_CURSOR\n}\n\nfunction formatCursor(\n cursorCharacter: string,\n cursorColor: Color | undefined,\n textColor: Color | undefined,\n): string {\n if (cursorColor)\n return colorize(cursorCharacter, cursorColor)\n\n if (textColor)\n return colorize(cursorCharacter, textColor)\n\n return cursorCharacter\n}\n\n/**\n * Typewriter effect component that reveals text character by character\n *\n * Simulates typing text with configurable speed, variance for realistic timing,\n * and an optional cursor. The cursor blinks while typing is in progress.\n *\n * @example\n * ```tsx\n * <Typewriter color=\"green\" cursor=\"â\" variance={0.5} speed={2}>\n * npm install ink-motion\n * </Typewriter>\n * ```\n */\nexport function Typewriter({\n children,\n color,\n cursor = DEFAULT_CURSOR,\n cursorColor,\n variance = DEFAULT_VARIANCE,\n delay = DEFAULT_DELAY,\n speed = DEFAULT_SPEED,\n enabled = true,\n onComplete,\n}: TypewriterProps) {\n const characters = splitChars(children)\n const totalCharacters = getTextLength(children)\n\n const visibleCharacters = useTypewriterProgress({\n totalCharacters,\n speed,\n variance,\n initialDelay: delay,\n enabled,\n onComplete,\n })\n\n const hasCompletedTyping = visibleCharacters >= totalCharacters\n const isCursorEnabled = cursor !== false\n\n const showCursor = useCursorBlink({\n enabled: enabled && isCursorEnabled,\n isComplete: hasCompletedTyping,\n })\n\n const displayText = useMemo(() => {\n const visibleText = characters.slice(FIRST_CHARACTER_INDEX, visibleCharacters).join('')\n const coloredText = color ? colorize(visibleText, color) : visibleText\n\n const shouldShowCursor = isCursorEnabled && showCursor && !hasCompletedTyping\n if (!shouldShowCursor)\n return coloredText\n\n const cursorCharacter = getCursorCharacter(cursor)\n const cursorText = formatCursor(cursorCharacter, cursorColor, color)\n\n return coloredText + cursorText\n }, [characters, visibleCharacters, color, cursor, cursorColor, showCursor, hasCompletedTyping, isCursorEnabled])\n\n return <Text>{displayText}</Text>\n}\n","import type { BaseEffectProps, Color } from '../types/index.js'\nimport { Text } from 'ink'\nimport { useMemo } from 'react'\nimport { useElapsedTime } from '../hooks/useElapsedTime.js'\nimport { colorize, interpolateColor } from '../utils/colors.js'\nimport { clamp } from '../utils/easing.js'\nimport { mapChars } from '../utils/text.js'\n\ntype WaveType = 'brightness' | 'vertical'\n\ninterface WaveProps extends BaseEffectProps {\n /**\n * Gradient colors for the wave [dark, bright]\n * @default ['#888888', '#ffffff']\n * @example ['#ec4899', '#8b5cf6']\n */\n colors?: [Color, Color]\n\n /**\n * Wave height (0-1)\n * @default 0.5\n */\n amplitude?: number\n\n /**\n * Number of wave cycles across text\n * @default 2\n */\n frequency?: number\n\n /**\n * Wave effect type\n * @default 'brightness'\n */\n type?: WaveType\n}\n\nconst DEFAULT_COLORS: [Color, Color] = ['#888888', '#ffffff']\nconst DEFAULT_AMPLITUDE = 0.5\nconst DEFAULT_FREQUENCY = 2\nconst DEFAULT_TYPE: WaveType = 'brightness'\nconst DEFAULT_SPEED = 1\nconst FULL_CIRCLE_RADIANS = Math.PI * 2\nconst WAVE_PERIOD_MS = 2000\nconst MIN_AMPLITUDE = 0\nconst MAX_AMPLITUDE = 1\nconst SINE_WAVE_OFFSET = 1\nconst SINE_WAVE_NORMALIZE = 0.5\nconst VERTICAL_SHIFT_THRESHOLD = 0.5\n\nfunction calculateWaveValue(\n characterIndex: number,\n time: number,\n frequency: number,\n amplitude: number,\n): number {\n const clampedAmplitude = clamp(amplitude, MIN_AMPLITUDE, MAX_AMPLITUDE)\n const safeFrequency = frequency || DEFAULT_FREQUENCY\n const waveLength = FULL_CIRCLE_RADIANS / safeFrequency\n const spatialComponent = (characterIndex / waveLength) * FULL_CIRCLE_RADIANS\n const temporalComponent = time * FULL_CIRCLE_RADIANS\n const phase = spatialComponent - temporalComponent\n const sineWave = Math.sin(phase)\n const normalizedSine = (sineWave + SINE_WAVE_OFFSET) * SINE_WAVE_NORMALIZE\n const amplitudeComplement = MAX_AMPLITUDE - clampedAmplitude\n return normalizedSine * clampedAmplitude + amplitudeComplement\n}\n\n/**\n * Wave effect component that creates a wave motion through text\n *\n * Animates text with a sine wave pattern that can affect brightness or vertical position.\n * The wave continuously flows through the text.\n *\n * @example\n * ```tsx\n * <Wave colors={['#ec4899', '#8b5cf6']} amplitude={0.7} frequency={3}>\n * ~~ wavy text ~~\n * </Wave>\n * ```\n */\nexport function Wave({\n children,\n colors = DEFAULT_COLORS,\n amplitude = DEFAULT_AMPLITUDE,\n frequency = DEFAULT_FREQUENCY,\n type = DEFAULT_TYPE,\n speed = DEFAULT_SPEED,\n enabled = true,\n}: WaveProps) {\n const elapsedTime = useElapsedTime(enabled, speed)\n const normalizedTime = elapsedTime / WAVE_PERIOD_MS\n\n const waveText = useMemo(() => {\n if (type === 'brightness') {\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const [darkColor, brightColor] = colors\n const characterColor = interpolateColor(darkColor, brightColor, waveValue)\n return colorize(character, characterColor)\n })\n }\n\n return mapChars(children, (character, index) => {\n const waveValue = calculateWaveValue(index, normalizedTime, frequency, amplitude)\n const shouldShift = waveValue > VERTICAL_SHIFT_THRESHOLD\n return shouldShift ? ` ${character}` : character\n })\n }, [children, normalizedTime, colors, amplitude, frequency, type])\n\n return <Text>{waveText}</Text>\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ink-motion",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"description": "Motion and animation components for Ink - beautiful text effects for your CLI",
|
|
6
6
|
"author": "James Glenn",
|
|
7
7
|
"license": "MIT",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"dev": "tsup --watch",
|
|
52
52
|
"demo": "bun examples/demo.tsx",
|
|
53
53
|
"test": "bun test",
|
|
54
|
+
"test:file": "f() { bun test tests/${1:-*}.test.tsx; }; f",
|
|
54
55
|
"type-check": "tsc --noEmit",
|
|
55
56
|
"lint": "eslint .",
|
|
56
57
|
"prepublishOnly": "bun run build && publint"
|