react-animated-waves 1.0.10 → 1.1.0
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 +100 -6
- package/dist/index.d.ts +48 -7
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +36 -19
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ $ npm install react-animated-waves
|
|
|
33
33
|
|
|
34
34
|
## Demo
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Try the [interactive demo][demo] to preview wave presets and explore possible configurations.
|
|
37
37
|
|
|
38
38
|
## Usage
|
|
39
39
|
|
|
@@ -42,17 +42,109 @@ Import the `Waves` component from `react-animated-waves` and use it in your Reac
|
|
|
42
42
|
```jsx
|
|
43
43
|
import { Waves } from "react-animated-waves";
|
|
44
44
|
|
|
45
|
-
<
|
|
45
|
+
<div style={{ width: "100%", height: 240 }}>
|
|
46
|
+
<Waves
|
|
47
|
+
amplitude={24}
|
|
48
|
+
colors={["#FF6AC6", "#436EDB", "#FF6AC6"]}
|
|
49
|
+
height="100%"
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
For voice or audio UIs, drive wave height with the `intensity` prop. Pass a normalized value between `0` _(flat)_ and `1` _(amplitude)_. For example, using microphone input as shown below:
|
|
55
|
+
|
|
56
|
+
```jsx
|
|
57
|
+
import { useEffect, useState } from "react";
|
|
58
|
+
import { Waves } from "react-animated-waves";
|
|
59
|
+
|
|
60
|
+
function VoiceWaveform() {
|
|
61
|
+
const [intensity, setIntensity] = useState(0);
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
let stream;
|
|
65
|
+
let audioContext;
|
|
66
|
+
let rafId;
|
|
67
|
+
|
|
68
|
+
async function startMic() {
|
|
69
|
+
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
70
|
+
audioContext = new AudioContext();
|
|
71
|
+
const analyser = audioContext.createAnalyser();
|
|
72
|
+
audioContext.createMediaStreamSource(stream).connect(analyser);
|
|
73
|
+
|
|
74
|
+
const data = new Uint8Array(analyser.fftSize);
|
|
75
|
+
const tick = () => {
|
|
76
|
+
analyser.getByteTimeDomainData(data);
|
|
77
|
+
let sum = 0;
|
|
78
|
+
for (const sample of data) {
|
|
79
|
+
const normalized = (sample - 128) / 128;
|
|
80
|
+
sum += normalized * normalized;
|
|
81
|
+
}
|
|
82
|
+
setIntensity(Math.min(1, Math.sqrt(sum / data.length) * 4));
|
|
83
|
+
rafId = requestAnimationFrame(tick);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
tick();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
startMic().catch(console.error);
|
|
90
|
+
|
|
91
|
+
return () => {
|
|
92
|
+
cancelAnimationFrame(rafId);
|
|
93
|
+
stream?.getTracks().forEach((track) => track.stop());
|
|
94
|
+
void audioContext?.close();
|
|
95
|
+
};
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<Waves
|
|
100
|
+
amplitude={40}
|
|
101
|
+
intensity={intensity}
|
|
102
|
+
smoothing={0.2}
|
|
103
|
+
speed={1.3}
|
|
104
|
+
colors={["#436EDB", "#8B5CF6"]}
|
|
105
|
+
height={180}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Advanced Usage
|
|
112
|
+
|
|
113
|
+
For specific waveforms, pass custom layer definitions with the `layers` prop. Use the [interactive demo][demo] to experiment with layer values in real-time.
|
|
114
|
+
|
|
115
|
+
```jsx
|
|
116
|
+
<Waves
|
|
117
|
+
amplitude={30}
|
|
118
|
+
colors={["#436EDB", "#FF6AC6"]}
|
|
119
|
+
layers={[
|
|
120
|
+
{ amplitudeMultiplier: 1, frequency: 0.02, alpha: 0.6, speed: 0.001, meshCount: 20 },
|
|
121
|
+
{ amplitudeMultiplier: 0.5, frequency: 0.035, alpha: 0.35, speed: 0.005, meshCount: 12 },
|
|
122
|
+
]}
|
|
123
|
+
/>
|
|
46
124
|
```
|
|
47
125
|
|
|
48
126
|
### Props
|
|
49
127
|
|
|
50
128
|
The `Waves` component accepts the following props:
|
|
51
129
|
|
|
52
|
-
| Prop
|
|
53
|
-
|
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
130
|
+
| Prop | Description | Default |
|
|
131
|
+
| --- | --- | --- |
|
|
132
|
+
| `colors` | The colors for the waveform. Accepts any CSS color string (e.g., `#436EDB`, `rgb(67, 110, 219)`, `#436EDB80`). | `['#436EDB']` |
|
|
133
|
+
| `amplitude` | Maximum height of the waveform in pixels. | `20` |
|
|
134
|
+
| `speed` | Speed of the waveform animation. | `1` |
|
|
135
|
+
| `smoothing` | Smoothing factor while approaching the target amplitude. | `0.1` |
|
|
136
|
+
| `frequency` | Sine wave frequency of the waveform. | `1` |
|
|
137
|
+
| `waveCount` | Number of primary wave layers. | `3` |
|
|
138
|
+
| `lineCount` | Number of secondary mesh lines. | `30` |
|
|
139
|
+
| `pinch` | Pinch intensity at the canvas edges. | `6` |
|
|
140
|
+
| `opacity` | Opacity of the waveform gradient stops. | `1` |
|
|
141
|
+
| `amplitudeOscillation` | Oscillation factor applied to the amplitude over time. | `0.05` |
|
|
142
|
+
| `height` | Height of the canvas in pixels, or a CSS length such as `100%`. | parent height or `150` |
|
|
143
|
+
| `pixelRatio` | Pixel ratio of the canvas. | `auto` |
|
|
144
|
+
| `respectReducedMotion` | Respect the user's reduced motion preference. | `true` |
|
|
145
|
+
| `paused` | Pause the animation. | `false` |
|
|
146
|
+
| `intensity` | Activity multiplier for the waveform for dynamic intensity between `0` (flat) and `1` (configured amplitude). | `1` |
|
|
147
|
+
| `layers` | Custom layer configuration overrides. | generated defaults |
|
|
56
148
|
|
|
57
149
|
## Contributing
|
|
58
150
|
|
|
@@ -61,3 +153,5 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to report issu
|
|
|
61
153
|
## License
|
|
62
154
|
|
|
63
155
|
[MIT](LICENSE) © [Rohit Agrawal](https://github.com/agrawal-rohit)
|
|
156
|
+
|
|
157
|
+
[demo]: https://codesandbox.io/p/sandbox/react-animated-waves-example-6z9hlh
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/** Per-layer overrides for advanced wave configuration. */
|
|
3
|
+
type WaveLayer = {
|
|
4
|
+
/** Multiplier applied to the current amplitude for this layer. */amplitudeMultiplier?: number; /** Horizontal wave frequency. */
|
|
5
|
+
frequency?: number; /** Phase speed multiplier for this layer. */
|
|
6
|
+
speed?: number; /** Base opacity for this layer's gradient stops. */
|
|
7
|
+
alpha?: number; /** Number of secondary mesh lines drawn around this layer. */
|
|
8
|
+
meshCount?: number; /** Static phase offset applied when drawing this layer. */
|
|
9
|
+
phaseOffset?: number;
|
|
10
|
+
};
|
|
11
|
+
/** Public props for the `Waves` canvas component. */
|
|
12
|
+
type WavesProps = Omit<React.CanvasHTMLAttributes<HTMLCanvasElement>, "height"> & {
|
|
13
|
+
/** The colors for the waveform. Accepts any CSS color string (e.g., `#436EDB`, `rgb(67, 110, 219)`, `#436EDB80`). */colors?: string[]; /** Maximum height of the waveform in pixels. */
|
|
14
|
+
amplitude?: number; /** Speed of the waveform animation. */
|
|
15
|
+
speed?: number; /** Smoothing factor while approaching the target amplitude. */
|
|
16
|
+
smoothing?: number; /** Sine wave frequency of the waveform. */
|
|
17
|
+
frequency?: number; /** Number of primary wave layers. */
|
|
18
|
+
waveCount?: number; /** Number of secondary mesh lines. */
|
|
19
|
+
lineCount?: number; /** Pinch intensity at the canvas edges. */
|
|
20
|
+
pinch?: number; /** Opacity of the waveform gradient stops. */
|
|
21
|
+
opacity?: number; /** Oscillation factor applied to the amplitude over time. */
|
|
22
|
+
amplitudeOscillation?: number; /** Height of the canvas in pixels, or a CSS length such as `100%`. */
|
|
23
|
+
height?: number | string; /** Pixel ratio of the canvas. */
|
|
24
|
+
pixelRatio?: number | "auto"; /** Respect the user's reduced motion preference. */
|
|
25
|
+
respectReducedMotion?: boolean; /** Pause the animation. */
|
|
26
|
+
paused?: boolean; /** Activity multiplier for the waveform for dynamic intensity between 0 (flat) and 1 (configured amplitude). */
|
|
27
|
+
intensity?: number; /** Custom layer configuration overrides. */
|
|
28
|
+
layers?: WaveLayer[];
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
3
31
|
//#region src/waves.d.ts
|
|
4
|
-
|
|
5
|
-
|
|
32
|
+
declare const Waves: import("react").NamedExoticComponent<Omit<import("react").CanvasHTMLAttributes<HTMLCanvasElement>, "height"> & {
|
|
33
|
+
colors?: string[];
|
|
6
34
|
amplitude?: number;
|
|
7
|
-
|
|
8
|
-
|
|
35
|
+
speed?: number;
|
|
36
|
+
smoothing?: number;
|
|
37
|
+
frequency?: number;
|
|
38
|
+
waveCount?: number;
|
|
39
|
+
lineCount?: number;
|
|
40
|
+
pinch?: number;
|
|
41
|
+
opacity?: number;
|
|
42
|
+
amplitudeOscillation?: number;
|
|
43
|
+
height?: number | string;
|
|
44
|
+
pixelRatio?: number | "auto";
|
|
45
|
+
respectReducedMotion?: boolean;
|
|
46
|
+
paused?: boolean;
|
|
47
|
+
intensity?: number;
|
|
48
|
+
layers?: WaveLayer[];
|
|
49
|
+
} & import("react").RefAttributes<HTMLCanvasElement>>;
|
|
9
50
|
//#endregion
|
|
10
|
-
export { Waves };
|
|
51
|
+
export { type WaveLayer, Waves, type WavesProps };
|
|
11
52
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{forwardRef as e,memo as t,useCallback as n,useEffect as r,useImperativeHandle as i,useLayoutEffect as a,useMemo as o,useRef as s}from"react";import{TinyColor as c}from"@ctrl/tinycolor";import{jsx as l}from"react/jsx-runtime";const u=(e,t)=>new c(e).setAlpha(Math.max(0,t)).toRgbString(),d=(e,t,n)=>{let r=`${t.join(`|`)}:${n.toFixed(3)}`,i=e.get(r);if(i)return i;let a=t.map((e,r)=>({offset:t.length>1?r/(t.length-1):0,color:u(e,n)}));return e.set(r,a),a},f=e=>e===`auto`||e===void 0?globalThis.window===void 0?1:globalThis.window.devicePixelRatio||1:e,p=(e,t)=>{if(e===void 0)return t>0?t:150;if(typeof e==`number`)return e;if(e.endsWith(`%`))return t>0?t*Number.parseFloat(e)/100:150;let n=Number.parseFloat(e);return Number.isFinite(n)?n:150},m=(e,t,n)=>{if(!e)return null;let r=e.parentElement,i=r?.clientWidth||e.clientWidth||300,a=p(t,r?.clientHeight||0),o=f(n),s=Math.max(1,i),c=Math.max(1,Math.floor(a));e.width=Math.max(1,Math.floor(s*o)),e.height=Math.max(1,Math.floor(c*o)),e.style.width=`${s}px`,e.style.height=`${c}px`;let l=e.getContext(`2d`);return l&&`setTransform`in l&&l.setTransform(o,0,0,o,0,0),{width:s,height:c}},h=(e,t,n,r,i,a)=>{let o=d(r,i,a),s=e.createLinearGradient(0,0,t,n);for(let e of o)s.addColorStop(e.offset,e.color);return s},g=(e,t,n,r,i,a,o,s)=>{e.strokeStyle=a,e.beginPath();for(let a=0;a<t;a++){let c=Math.sin(a/t*Math.PI)**s,l=r*Math.sin(i*a+o)*c;e.lineTo(a,n/2+l)}e.stroke()},_=({ctx:e,colors:t,config:n,gradientCache:r,layoutWidth:i,layoutHeight:a,oscillatingAmplitude:o,timestamp:s})=>{for(let c of n.layers){let l=o*c.amplitudeMultiplier,u=s*c.speed+c.phaseOffset;g(e,i,a,l,c.frequency,h(e,i,a,r,t,c.alpha),u,n.pinch);for(let o=0;o<c.meshCount;o++)g(e,i,a,l-o*.1,c.frequency+o*25e-5,h(e,i,a,r,t,c.alpha*.6-o*.01),s*c.speed+o*.015+c.phaseOffset,n.pinch)}},v=[`#436EDB`],y=[{amplitudeMultiplier:1,frequency:.02,alpha:.6,speed:.001,meshCount:30,phaseOffset:0},{amplitudeMultiplier:.6,frequency:.03,alpha:.4,speed:.004,meshCount:30,phaseOffset:0},{amplitudeMultiplier:.3,frequency:.04,alpha:.2,speed:.007,meshCount:30,phaseOffset:0}],b=(e,t,n)=>{let r=y[t]??y.at(-1);return{amplitudeMultiplier:e.amplitudeMultiplier??r.amplitudeMultiplier,frequency:e.frequency??r.frequency,alpha:e.alpha??r.alpha,speed:e.speed??r.speed,meshCount:e.meshCount??n,phaseOffset:e.phaseOffset??0}},x=(e,t,n,r,i)=>e===3&&t===1&&n===1&&r===1&&i===30?y.map(e=>({...e,meshCount:i})):Array.from({length:e},(a,o)=>{let s=e>1?o/(e-1):0;return{amplitudeMultiplier:1-s*.7,frequency:(.02+s*.02)*t,alpha:(.6-s*.4)*n,speed:(.001+s*.006)*r,meshCount:i,phaseOffset:0}}),S=({speed:e=1,smoothing:t=.1,frequency:n=1,waveCount:r=3,lineCount:i=30,pinch:a=6,opacity:o=1,amplitudeOscillation:s=.05,layers:c}={})=>{let l=c?.length?c.map((e,t)=>b(e,t,i)):x(r,n,o,e,i);return{smoothing:t,amplitudeOscillation:s,timeScale:.0015*e,pinch:a,layers:l}},C=e=>e===void 0?1:Math.min(1,Math.max(0,e)),w=e(({amplitude:e=20,colors:t=v,speed:c,smoothing:u,frequency:d,waveCount:f,lineCount:p,pinch:h,opacity:g,amplitudeOscillation:y,height:b,pixelRatio:x=`auto`,respectReducedMotion:w=!0,paused:T=!1,intensity:E,layers:D,...O},k)=>{let A=s(null),j=s(e),M=s(e),N=s(new Map),P=s({width:300,height:150}),F=s(null),I=o(()=>S({speed:c,smoothing:u,frequency:d,waveCount:f,lineCount:p,pinch:h,opacity:g,amplitudeOscillation:y,layers:D}),[c,u,d,f,p,h,g,y,D]),L=C(E);i(k,()=>A.current,[]),r(()=>{M.current=e*L},[e,L]);let R=n(()=>{let e=m(A.current,b,x);e&&(P.current=e)},[b,x]);return a(()=>{R();let e=A.current?.parentElement;if(!e||typeof ResizeObserver>`u`){F.current?.();return}let t=new ResizeObserver(()=>{R(),F.current?.()});return t.observe(e),()=>t.disconnect()},[R]),r(()=>{let e=0,n=A.current,r=n?.getContext(`2d`);if(!n||!r)return;N.current.clear();let i=globalThis.window!==void 0&&w?globalThis.window.matchMedia(`(prefers-reduced-motion: reduce)`):null,a=()=>!(T||typeof document<`u`&&document.hidden||i?.matches),o=()=>{let e=Date.now(),n=e*I.timeScale;j.current+=I.smoothing*(M.current-j.current);let i=I.amplitudeOscillation===0?j.current:j.current*(1+Math.sin(n)*I.amplitudeOscillation);r.clearRect(0,0,P.current.width,P.current.height),_({ctx:r,colors:t,config:I,gradientCache:N.current,layoutWidth:P.current.width,layoutHeight:P.current.height,oscillatingAmplitude:i,timestamp:e})},s=()=>{a()&&(o(),e=requestAnimationFrame(s))};F.current=o,R(),o(),a()&&(e=requestAnimationFrame(s));let c=()=>{!document.hidden&&a()&&(o(),e=requestAnimationFrame(s))},l=()=>{a()&&(o(),e=requestAnimationFrame(s))};return document.addEventListener(`visibilitychange`,c),i?.addEventListener(`change`,l),()=>{F.current=null,cancelAnimationFrame(e),document.removeEventListener(`visibilitychange`,c),i?.removeEventListener(`change`,l)}},[t,T,w,R,I]),l(`canvas`,{ref:A,"aria-hidden":O[`aria-hidden`]??!0,width:`100%`,height:`auto`,...O})});w.displayName=`Waves`;const T=t(w);export{T as Waves};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/utils.ts","../src/waves.tsx"],"sourcesContent":["/**\n * Linearly interpolates between two numeric values.\n *\n * Given a start value `a` and an end value `b`, returns the value that lies\n * `t` fraction of the way from `a` to `b`. The interpolation factor `t` is\n * typically in the range [0, 1], where 0 returns `a` and 1 returns `b`.\n * No clamping is performed on `t` (values outside [0, 1] will extrapolate).\n *\n * @param a - Start value.\n * @param b - End value.\n * @param t - Interpolation factor between 0 and 1 (no automatic clamping).\n * @returns The interpolated numeric value at fraction `t` between `a` and `b`.\n *\n * @example\n * lerp(0, 10, 0.5); // returns 5\n */\nexport const lerp = (a: number, b: number, t: number): number => {\n\treturn a + t * (b - a);\n};\n\n/**\n * Convert a hexadecimal color to an rgba(...) CSS string.\n *\n * The `hex` parameter may optionally start with a leading '#'. This function\n * expects a 6-digit hexadecimal color (e.g. \"#aabbcc\" or \"aabbcc\"). The\n * returned string is a valid CSS `rgba(r, g, b, a)` representation where\n * `r`, `g`, and `b` are integer values in [0, 255] and `a` is the supplied\n * alpha value.\n *\n * Note: This function does not perform strict validation on the `hex` input.\n * Passing non-hex characters or an incorrectly sized hex string may produce\n * unexpected results.\n *\n * @param hex - Hex color string (with or without leading '#'), expected 6 hex digits.\n * @param alpha - Opacity value between 0 and 1 (default: 1).\n * @returns A CSS rgba(...) string representing the color and alpha.\n *\n * @example\n * hexToRgba('#ff0000', 0.5); // returns \"rgba(255, 0, 0, 0.5)\"\n */\nexport const hexToRgba = (hex: string, alpha: number = 1): string => {\n\tif (hex.startsWith(\"#\")) {\n\t\thex = hex.slice(1);\n\t}\n\n\tconst bigint = Number.parseInt(hex, 16);\n\tconst r = (bigint >> 16) & 255;\n\tconst g = (bigint >> 8) & 255;\n\tconst b = bigint & 255;\n\n\treturn `rgba(${r}, ${g}, ${b}, ${alpha})`;\n};\n","import { memo, useCallback, useEffect, useRef } from \"react\";\nimport { hexToRgba, lerp } from \"./utils\";\n\n// Define the properties for the AnimatedWaveform component\ntype WavesProps = React.DetailedHTMLProps<\n\tReact.CanvasHTMLAttributes<HTMLCanvasElement>,\n\tHTMLCanvasElement\n> & {\n\t/** The colors for the waveform */\n\tcolors?: string[];\n\t/** The amplitude of the waveform */\n\tamplitude?: number;\n};\n\nexport const Waves = memo<WavesProps>(\n\t({ amplitude = 20, colors = [\"#436EDB\"], ...props }) => {\n\t\tconst amplitudeRef = useRef(amplitude);\n\t\tconst canvasRef = useRef<HTMLCanvasElement>(null);\n\t\tconst targetAmplitudeRef = useRef<number>(amplitude);\n\n\t\t// Update the target amplitude whenever the amplitude prop changes\n\t\tuseEffect(() => {\n\t\t\ttargetAmplitudeRef.current = amplitude;\n\t\t}, [amplitude]);\n\n\t\t// Function to draw the waveform on the canvas\n\t\tconst drawWaveform = useCallback(\n\t\t\t(\n\t\t\t\tctx: CanvasRenderingContext2D,\n\t\t\t\tamplitude: number,\n\t\t\t\tfrequency: number,\n\t\t\t\tcolor: string | CanvasGradient,\n\t\t\t\tphase = 0,\n\t\t\t) => {\n\t\t\t\tctx.strokeStyle = color;\n\t\t\t\tctx.beginPath();\n\n\t\t\t\t// Draw the waveform\n\t\t\t\tfor (let i = 0; i < ctx.canvas.width; i++) {\n\t\t\t\t\t// Compute the pinching effect\n\t\t\t\t\tconst sineWave = Math.sin(Math.PI * (i / ctx.canvas.width));\n\t\t\t\t\tconst pinch = sineWave ** 6;\n\n\t\t\t\t\t// Calculate the y position with sine function, pinch effect, and time-based phase shift\n\t\t\t\t\tconst y = amplitude * Math.sin(frequency * i + phase) * pinch;\n\n\t\t\t\t\tctx.lineTo(i, ctx.canvas.height / 2 + y);\n\t\t\t\t}\n\n\t\t\t\tctx.stroke();\n\t\t\t},\n\t\t\t[],\n\t\t);\n\n\t\t// Animate the waveform\n\t\tuseEffect(() => {\n\t\t\tlet animationFrameId: number;\n\t\t\tconst canvas = canvasRef.current as HTMLCanvasElement;\n\t\t\tconst ctx = canvas.getContext(\"2d\");\n\t\t\tif (!ctx) return;\n\t\t\tconst parent = canvas.parentElement;\n\t\t\tif (parent) canvas.width = parent.clientWidth;\n\n\t\t\tconst animate = () => {\n\t\t\t\t// Convert milliseconds to seconds and increase speed\n\t\t\t\tconst time = Date.now() * 0.0015;\n\n\t\t\t\tamplitudeRef.current = lerp(\n\t\t\t\t\tamplitudeRef.current,\n\t\t\t\t\ttargetAmplitudeRef.current,\n\t\t\t\t\t0.1,\n\t\t\t\t);\n\n\t\t\t\t// Create an oscillating effect with amplitude\n\t\t\t\tconst oscillatingAmplitude =\n\t\t\t\t\tamplitudeRef.current * (1 + Math.sin(time) * 0.05);\n\n\t\t\t\tctx.clearRect(0, 0, canvas.width, canvas.height);\n\n\t\t\t\t// Define primary waveforms with their respective amplitudes, frequencies, and colors\n\t\t\t\tconst primaryWaveforms = [\n\t\t\t\t\t{\n\t\t\t\t\t\tamplitude: oscillatingAmplitude,\n\t\t\t\t\t\tfrequency: 0.02,\n\t\t\t\t\t\talpha: 0.6,\n\t\t\t\t\t\tspeed: 0.001,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tamplitude: oscillatingAmplitude * 0.6,\n\t\t\t\t\t\tfrequency: 0.03,\n\t\t\t\t\t\talpha: 0.4,\n\t\t\t\t\t\tspeed: 0.004,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tamplitude: oscillatingAmplitude * 0.3,\n\t\t\t\t\t\tfrequency: 0.04,\n\t\t\t\t\t\talpha: 0.2,\n\t\t\t\t\t\tspeed: 0.007,\n\t\t\t\t\t},\n\t\t\t\t];\n\n\t\t\t\t// For each primary waveform, draw the waveform and its surrounding mesh\n\t\t\t\tfor (const primary of primaryWaveforms) {\n\t\t\t\t\tconst gradient = ctx.createLinearGradient(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tcanvas.width,\n\t\t\t\t\t\tcanvas.height,\n\t\t\t\t\t);\n\t\t\t\t\tconst stopIncrement = colors.length > 1 ? 1 / (colors.length - 1) : 0;\n\t\t\t\t\tcolors.forEach((color, index) => {\n\t\t\t\t\t\tgradient.addColorStop(\n\t\t\t\t\t\t\tstopIncrement * index,\n\t\t\t\t\t\t\thexToRgba(color, primary.alpha),\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\n\t\t\t\t\tdrawWaveform(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\tprimary.amplitude,\n\t\t\t\t\t\tprimary.frequency,\n\t\t\t\t\t\tgradient,\n\t\t\t\t\t\tDate.now() * primary.speed,\n\t\t\t\t\t);\n\n\t\t\t\t\t// Draw secondary waveforms around the primary waveform\n\t\t\t\t\tfor (let i = 0; i < 30; i++) {\n\t\t\t\t\t\tconst amp = primary.amplitude - i * 0.1;\n\t\t\t\t\t\tconst freq = primary.frequency + i * 0.00025;\n\t\t\t\t\t\tconst alpha = primary.alpha * 0.6 - i * 0.01;\n\t\t\t\t\t\tconst gradient = ctx.createLinearGradient(\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tcanvas.width,\n\t\t\t\t\t\t\tcanvas.height,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst stopIncrement =\n\t\t\t\t\t\t\tcolors.length > 1 ? 1 / (colors.length - 1) : 0;\n\t\t\t\t\t\tcolors.forEach((color, index) => {\n\t\t\t\t\t\t\tgradient.addColorStop(\n\t\t\t\t\t\t\t\tstopIncrement * index,\n\t\t\t\t\t\t\t\thexToRgba(color, alpha),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tdrawWaveform(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\tamp,\n\t\t\t\t\t\t\tfreq,\n\t\t\t\t\t\t\tgradient,\n\t\t\t\t\t\t\tDate.now() * primary.speed + i * 0.015,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tanimationFrameId = requestAnimationFrame(animate);\n\t\t\t};\n\n\t\t\tanimate();\n\n\t\t\t// Clean up the animation frame when the component unmounts\n\t\t\treturn () => {\n\t\t\t\tcancelAnimationFrame(animationFrameId);\n\t\t\t};\n\t\t}, [colors, drawWaveform]);\n\n\t\treturn (\n\t\t\t<canvas ref={canvasRef} width=\"100%\" height=\"auto\" {...props}></canvas>\n\t\t);\n\t},\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/color.ts","../src/canvas.ts","../src/config.ts","../src/waves.tsx"],"sourcesContent":["import { TinyColor } from \"@ctrl/tinycolor\";\n\n/**\n * Convert a CSS color string to an rgba(...) value with the given alpha.\n * @param color - The CSS color string to convert.\n * @param alpha - The alpha value to apply to the color.\n * @returns The rgba(...) value with the given alpha.\n */\nexport const colorWithAlpha = (color: string, alpha: number) =>\n\tnew TinyColor(color).setAlpha(Math.max(0, alpha)).toRgbString();\n\nexport type GradientStops = {\n\toffset: number;\n\tcolor: string;\n}[];\n\nexport type GradientCache = Map<string, GradientStops>;\n\n/**\n * Resolve linear-gradient stop data for a palette and opacity, reusing cached results.\n * @param cache - Gradient stop cache keyed by palette and alpha.\n * @param colors - The colors to build the gradient stops for.\n * @param alpha - The alpha value to apply to the colors.\n * @returns The gradient stops.\n */\nexport const getGradientStops = (\n\tcache: GradientCache,\n\tcolors: string[],\n\talpha: number,\n) => {\n\tconst key = `${colors.join(\"|\")}:${alpha.toFixed(3)}`;\n\tconst cached = cache.get(key);\n\tif (cached) return cached;\n\n\tconst stops = colors.map((color, index) => ({\n\t\toffset: colors.length > 1 ? index / (colors.length - 1) : 0,\n\t\tcolor: colorWithAlpha(color, alpha),\n\t}));\n\tcache.set(key, stops);\n\treturn stops;\n};\n","import { type GradientCache, getGradientStops } from \"./color\";\nimport type { resolveWaveConfig } from \"./config\";\nimport type { WavesProps } from \"./types\";\n\n/**\n * Resolve the device pixel ratio used for the canvas backing store.\n * @param pixelRatio - The pixel ratio to use for the canvas.\n * @returns The device pixel ratio.\n */\nexport const getPixelRatio = (pixelRatio: WavesProps[\"pixelRatio\"]) => {\n\tif (pixelRatio === \"auto\" || pixelRatio === undefined) {\n\t\treturn globalThis.window === undefined\n\t\t\t? 1\n\t\t\t: globalThis.window.devicePixelRatio || 1;\n\t}\n\n\treturn pixelRatio;\n};\n\n/**\n * Resolve the canvas height in CSS pixels from the height prop and parent size.\n * @param height - The height of the canvas.\n * @param parentHeight - The height of the parent element.\n * @returns The canvas height in CSS pixels.\n */\nexport const resolveCanvasHeight = (\n\theight: WavesProps[\"height\"],\n\tparentHeight: number,\n) => {\n\tif (height === undefined) return parentHeight > 0 ? parentHeight : 150;\n\n\tif (typeof height === \"number\") return height;\n\n\tif (height.endsWith(\"%\")) {\n\t\tif (parentHeight > 0)\n\t\t\treturn (parentHeight * Number.parseFloat(height)) / 100;\n\n\t\t// Parent may not be measured yet; fall back until ResizeObserver runs.\n\t\treturn 150;\n\t}\n\n\tconst parsedHeight = Number.parseFloat(height);\n\treturn Number.isFinite(parsedHeight) ? parsedHeight : 150;\n};\n\n/**\n * Sync canvas CSS and backing-store dimensions.\n * @param canvas - The canvas element to apply the layout to.\n * @param height - The height of the canvas.\n * @param pixelRatio - The pixel ratio to use for the canvas.\n * @returns The layout width and height.\n */\nexport const applyCanvasLayout = (\n\tcanvas: HTMLCanvasElement | null,\n\theight: WavesProps[\"height\"],\n\tpixelRatio: WavesProps[\"pixelRatio\"],\n) => {\n\tif (!canvas) return null;\n\n\tconst parent = canvas.parentElement;\n\tconst layoutWidthValue = parent?.clientWidth || canvas.clientWidth || 300;\n\tconst layoutHeightValueRaw = resolveCanvasHeight(\n\t\theight,\n\t\tparent?.clientHeight || 0,\n\t);\n\tconst ratio = getPixelRatio(pixelRatio);\n\tconst layoutWidth = Math.max(1, layoutWidthValue);\n\tconst layoutHeightValue = Math.max(1, Math.floor(layoutHeightValueRaw));\n\n\t// Backing-store pixels are scaled for retina; drawing uses layout coordinates.\n\tcanvas.width = Math.max(1, Math.floor(layoutWidth * ratio));\n\tcanvas.height = Math.max(1, Math.floor(layoutHeightValue * ratio));\n\tcanvas.style.width = `${layoutWidth}px`;\n\tcanvas.style.height = `${layoutHeightValue}px`;\n\n\tconst ctx = canvas.getContext(\"2d\");\n\tif (ctx && \"setTransform\" in ctx) {\n\t\tctx.setTransform(ratio, 0, 0, ratio, 0, 0);\n\t}\n\n\treturn {\n\t\twidth: layoutWidth,\n\t\theight: layoutHeightValue,\n\t};\n};\n\n/**\n * Create a diagonal canvas gradient for a wave layer.\n * @param ctx - The canvas context to use for the gradient.\n * @param width - The width of the canvas.\n * @param height - The height of the canvas.\n * @param cache - Gradient stop cache keyed by palette and alpha.\n * @param colors - The colors to use for the gradient stops.\n * @param alpha - The alpha value to use for the gradient stops.\n * @returns The canvas gradient.\n */\nconst createWaveGradient = (\n\tctx: CanvasRenderingContext2D,\n\twidth: number,\n\theight: number,\n\tcache: GradientCache,\n\tcolors: string[],\n\talpha: number,\n) => {\n\tconst stops = getGradientStops(cache, colors, alpha);\n\tconst gradient = ctx.createLinearGradient(0, 0, width, height);\n\tfor (const stop of stops) gradient.addColorStop(stop.offset, stop.color);\n\treturn gradient;\n};\n\n/**\n * Draw a single horizontal wave line using a sine curve and edge pinch envelope.\n * @param ctx - The canvas context to use for the waveform.\n * @param layoutWidth - The width of the waveform.\n * @param layoutHeight - The height of the waveform.\n * @param amplitude - The amplitude of the waveform.\n * @param frequency - The frequency of the waveform.\n * @param color - The color of the waveform.\n * @param phase - The phase of the waveform.\n * @param pinchExponent - The pinch exponent of the waveform.\n * @returns The drawn waveform.\n */\nconst drawWaveform = (\n\tctx: CanvasRenderingContext2D,\n\tlayoutWidth: number,\n\tlayoutHeight: number,\n\tamplitude: number,\n\tfrequency: number,\n\tcolor: string | CanvasGradient,\n\tphase: number,\n\tpinchExponent: number,\n) => {\n\tctx.strokeStyle = color;\n\tctx.beginPath();\n\n\tfor (let i = 0; i < layoutWidth; i++) {\n\t\t// Fade amplitude toward both edges so the wave tapers to a point.\n\t\tconst sineWave = Math.sin(Math.PI * (i / layoutWidth));\n\t\tconst pinch = sineWave ** pinchExponent;\n\t\tconst y = amplitude * Math.sin(frequency * i + phase) * pinch;\n\n\t\tctx.lineTo(i, layoutHeight / 2 + y);\n\t}\n\n\tctx.stroke();\n};\n\n/**\n * Draw each primary wave and its surrounding mesh of secondary lines.\n * @param ctx - The canvas context to use for the waveform.\n * @param colors - The colors to use for the waveform.\n * @param config - The configuration to use for the waveform.\n * @param gradientCache - The cache to use for the gradient stops.\n * @param layoutWidth - The width of the waveform.\n * @param layoutHeight - The height of the waveform.\n * @param oscillatingAmplitude - The oscillating amplitude of the waveform.\n * @param timestamp - The timestamp of the waveform.\n * @returns The drawn waveform.\n */\nexport const drawWaveLayers = ({\n\tctx,\n\tcolors,\n\tconfig,\n\tgradientCache,\n\tlayoutWidth,\n\tlayoutHeight,\n\toscillatingAmplitude,\n\ttimestamp,\n}: {\n\tctx: CanvasRenderingContext2D;\n\tcolors: string[];\n\tconfig: ReturnType<typeof resolveWaveConfig>;\n\tgradientCache: GradientCache;\n\tlayoutWidth: number;\n\tlayoutHeight: number;\n\toscillatingAmplitude: number;\n\ttimestamp: number;\n}) => {\n\tfor (const primary of config.layers) {\n\t\tconst primaryAmplitude = oscillatingAmplitude * primary.amplitudeMultiplier;\n\t\tconst primaryPhase = timestamp * primary.speed + primary.phaseOffset;\n\n\t\tdrawWaveform(\n\t\t\tctx,\n\t\t\tlayoutWidth,\n\t\t\tlayoutHeight,\n\t\t\tprimaryAmplitude,\n\t\t\tprimary.frequency,\n\t\t\tcreateWaveGradient(\n\t\t\t\tctx,\n\t\t\t\tlayoutWidth,\n\t\t\t\tlayoutHeight,\n\t\t\t\tgradientCache,\n\t\t\t\tcolors,\n\t\t\t\tprimary.alpha,\n\t\t\t),\n\t\t\tprimaryPhase,\n\t\t\tconfig.pinch,\n\t\t);\n\n\t\t// Secondary mesh lines create the dense woven look around each primary wave.\n\t\tfor (let meshIndex = 0; meshIndex < primary.meshCount; meshIndex++) {\n\t\t\tconst amp = primaryAmplitude - meshIndex * 0.1;\n\t\t\tconst freq = primary.frequency + meshIndex * 0.00025;\n\t\t\tconst alpha = primary.alpha * 0.6 - meshIndex * 0.01;\n\n\t\t\tdrawWaveform(\n\t\t\t\tctx,\n\t\t\t\tlayoutWidth,\n\t\t\t\tlayoutHeight,\n\t\t\t\tamp,\n\t\t\t\tfreq,\n\t\t\t\tcreateWaveGradient(\n\t\t\t\t\tctx,\n\t\t\t\t\tlayoutWidth,\n\t\t\t\t\tlayoutHeight,\n\t\t\t\t\tgradientCache,\n\t\t\t\t\tcolors,\n\t\t\t\t\talpha,\n\t\t\t\t),\n\t\t\t\ttimestamp * primary.speed + meshIndex * 0.015 + primary.phaseOffset,\n\t\t\t\tconfig.pinch,\n\t\t\t);\n\t\t}\n\t}\n};\n","import type { WaveLayer, WavesProps } from \"./types\";\n\n// Default values for the Waves component.\nexport const DEFAULT_COLORS = [\"#436EDB\"];\nexport const DEFAULT_AMPLITUDE = 20;\nconst BASE_TIME_SCALE = 0.0015;\nconst BASE_SMOOTHING = 0.1;\nconst BASE_FREQUENCY = 1;\nconst BASE_LINE_COUNT = 30;\nconst BASE_WAVE_COUNT = 3;\nconst BASE_PINCH = 6;\nconst BASE_OPACITY = 1;\nconst BASE_SPEED = 1;\nconst BASE_AMPLITUDE_OSCILLATION = 0.05;\n\n/** Default wave layers used by the Waves component. */\nconst DEFAULT_PRIMARY_LAYERS: Required<WaveLayer>[] = [\n\t{\n\t\tamplitudeMultiplier: 1,\n\t\tfrequency: 0.02,\n\t\talpha: 0.6,\n\t\tspeed: 0.001,\n\t\tmeshCount: BASE_LINE_COUNT,\n\t\tphaseOffset: 0,\n\t},\n\t{\n\t\tamplitudeMultiplier: 0.6,\n\t\tfrequency: 0.03,\n\t\talpha: 0.4,\n\t\tspeed: 0.004,\n\t\tmeshCount: BASE_LINE_COUNT,\n\t\tphaseOffset: 0,\n\t},\n\t{\n\t\tamplitudeMultiplier: 0.3,\n\t\tfrequency: 0.04,\n\t\talpha: 0.2,\n\t\tspeed: 0.007,\n\t\tmeshCount: BASE_LINE_COUNT,\n\t\tphaseOffset: 0,\n\t},\n];\n\nexport type ResolveWaveConfigInput = Pick<\n\tWavesProps,\n\t| \"speed\"\n\t| \"smoothing\"\n\t| \"frequency\"\n\t| \"waveCount\"\n\t| \"lineCount\"\n\t| \"pinch\"\n\t| \"opacity\"\n\t| \"amplitudeOscillation\"\n\t| \"layers\"\n>;\n\n/**\n * Merge a caller-provided layer with defaults.\n * @param layer - The caller-provided layer.\n * @param index - The index of the layer.\n * @param lineCount - The number of lines to draw.\n * @returns The merged layer.\n */\nconst resolveLayer = (\n\tlayer: WaveLayer,\n\tindex: number,\n\tlineCount: number,\n): Required<WaveLayer> => {\n\tconst fallback =\n\t\tDEFAULT_PRIMARY_LAYERS[index] ?? DEFAULT_PRIMARY_LAYERS.at(-1);\n\n\treturn {\n\t\tamplitudeMultiplier:\n\t\t\tlayer.amplitudeMultiplier ?? fallback.amplitudeMultiplier,\n\t\tfrequency: layer.frequency ?? fallback.frequency,\n\t\talpha: layer.alpha ?? fallback.alpha,\n\t\tspeed: layer.speed ?? fallback.speed,\n\t\tmeshCount: layer.meshCount ?? lineCount,\n\t\tphaseOffset: layer.phaseOffset ?? 0,\n\t};\n};\n\n/**\n * Generate evenly spaced waveform layers when the caller does not pass `layers`.\n * @param waveCount - The number of waves to generate.\n * @param frequencyScale - The frequency scale to apply to the waves.\n * @param opacityScale - The opacity scale to apply to the waves.\n * @param speedScale - The speed scale to apply to the waves.\n * @param lineCount - The number of lines to draw.\n * @returns The generated layers.\n */\nconst generateLayers = (\n\twaveCount: number,\n\tfrequencyScale: number,\n\topacityScale: number,\n\tspeedScale: number,\n\tlineCount: number,\n): Required<WaveLayer>[] => {\n\tif (\n\t\twaveCount === BASE_WAVE_COUNT &&\n\t\tfrequencyScale === 1 &&\n\t\topacityScale === 1 &&\n\t\tspeedScale === 1 &&\n\t\tlineCount === BASE_LINE_COUNT\n\t) {\n\t\treturn DEFAULT_PRIMARY_LAYERS.map((layer) => ({\n\t\t\t...layer,\n\t\t\tmeshCount: lineCount,\n\t\t}));\n\t}\n\n\treturn Array.from({ length: waveCount }, (_, index) => {\n\t\tconst t = waveCount > 1 ? index / (waveCount - 1) : 0;\n\n\t\treturn {\n\t\t\tamplitudeMultiplier: 1 - t * 0.7,\n\t\t\tfrequency: (0.02 + t * 0.02) * frequencyScale,\n\t\t\talpha: (0.6 - t * 0.4) * opacityScale,\n\t\t\tspeed: (0.001 + t * 0.006) * speedScale,\n\t\t\tmeshCount: lineCount,\n\t\t\tphaseOffset: 0,\n\t\t};\n\t});\n};\n\n/**\n * Normalize public props into renderer-ready animation settings.\n * @param speed - The speed of the waveform animation.\n * @param smoothing - The smoothing factor while approaching the target amplitude.\n * @param frequency - The sine wave frequency of the waveform.\n * @param waveCount - The number of waves to generate.\n * @param lineCount - The number of lines to draw.\n * @param pinch - The pinch intensity at the canvas edges.\n * @param opacity - The opacity of the waveform gradient stops.\n * @param amplitudeOscillation - The oscillation factor applied to the amplitude over time.\n * @param layers - The custom layer configuration overrides.\n * @returns The resolved wave configuration.\n */\nexport const resolveWaveConfig = ({\n\tspeed = BASE_SPEED,\n\tsmoothing = BASE_SMOOTHING,\n\tfrequency = BASE_FREQUENCY,\n\twaveCount = BASE_WAVE_COUNT,\n\tlineCount = BASE_LINE_COUNT,\n\tpinch = BASE_PINCH,\n\topacity = BASE_OPACITY,\n\tamplitudeOscillation = BASE_AMPLITUDE_OSCILLATION,\n\tlayers,\n}: ResolveWaveConfigInput = {}) => {\n\tconst resolvedLayers = layers?.length\n\t\t? layers.map((layer, index) => resolveLayer(layer, index, lineCount))\n\t\t: generateLayers(waveCount, frequency, opacity, speed, lineCount);\n\n\treturn {\n\t\tsmoothing,\n\t\tamplitudeOscillation,\n\t\ttimeScale: BASE_TIME_SCALE * speed,\n\t\tpinch,\n\t\tlayers: resolvedLayers,\n\t};\n};\n\n/**\n * Clamp a normalized activity level into the 0..1 range.\n * @param intensity - The normalized intensity of the waveform.\n * @returns The clamped intensity.\n */\nexport const clampIntensity = (intensity?: number) => {\n\tif (intensity === undefined) return 1;\n\treturn Math.min(1, Math.max(0, intensity));\n};\n","import {\n\tforwardRef,\n\tmemo,\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport { applyCanvasLayout, drawWaveLayers } from \"./canvas\";\nimport type { GradientCache } from \"./color\";\nimport {\n\tclampIntensity,\n\tDEFAULT_AMPLITUDE,\n\tDEFAULT_COLORS,\n\tresolveWaveConfig,\n} from \"./config\";\nimport type { WavesProps } from \"./types\";\n\n/** Canvas-based animated wave renderer. */\nconst WavesComponent = forwardRef<HTMLCanvasElement, WavesProps>(\n\t(\n\t\t{\n\t\t\tamplitude = DEFAULT_AMPLITUDE,\n\t\t\tcolors = DEFAULT_COLORS,\n\t\t\tspeed,\n\t\t\tsmoothing,\n\t\t\tfrequency,\n\t\t\twaveCount,\n\t\t\tlineCount,\n\t\t\tpinch,\n\t\t\topacity,\n\t\t\tamplitudeOscillation,\n\t\t\theight,\n\t\t\tpixelRatio = \"auto\",\n\t\t\trespectReducedMotion = true,\n\t\t\tpaused = false,\n\t\t\tintensity,\n\t\t\tlayers,\n\t\t\t...props\n\t\t},\n\t\tref,\n\t) => {\n\t\tconst canvasRef = useRef<HTMLCanvasElement>(null);\n\t\tconst amplitudeRef = useRef(amplitude);\n\t\tconst targetAmplitudeRef = useRef(amplitude);\n\t\tconst gradientCacheRef = useRef<GradientCache>(new Map());\n\t\tconst layoutSizeRef = useRef({ width: 300, height: 150 });\n\t\tconst renderFrameRef = useRef<(() => void) | null>(null);\n\n\t\tconst waveConfig = useMemo(\n\t\t\t() =>\n\t\t\t\tresolveWaveConfig({\n\t\t\t\t\tspeed,\n\t\t\t\t\tsmoothing,\n\t\t\t\t\tfrequency,\n\t\t\t\t\twaveCount,\n\t\t\t\t\tlineCount,\n\t\t\t\t\tpinch,\n\t\t\t\t\topacity,\n\t\t\t\t\tamplitudeOscillation,\n\t\t\t\t\tlayers,\n\t\t\t\t}),\n\t\t\t[\n\t\t\t\tspeed,\n\t\t\t\tsmoothing,\n\t\t\t\tfrequency,\n\t\t\t\twaveCount,\n\t\t\t\tlineCount,\n\t\t\t\tpinch,\n\t\t\t\topacity,\n\t\t\t\tamplitudeOscillation,\n\t\t\t\tlayers,\n\t\t\t],\n\t\t);\n\n\t\tconst intensityMultiplier = clampIntensity(intensity);\n\n\t\t// Expose the canvas element to the parent component.\n\t\tuseImperativeHandle(ref, () => canvasRef.current as HTMLCanvasElement, []);\n\n\t\t// Update the target amplitude based on the intensity.\n\t\tuseEffect(() => {\n\t\t\ttargetAmplitudeRef.current = amplitude * intensityMultiplier;\n\t\t}, [amplitude, intensityMultiplier]);\n\n\t\t// Apply the canvas layout and update the layout size reference.\n\t\tconst resizeCanvas = useCallback(() => {\n\t\t\tconst layout = applyCanvasLayout(canvasRef.current, height, pixelRatio);\n\t\t\tif (layout) layoutSizeRef.current = layout;\n\t\t}, [height, pixelRatio]);\n\n\t\t// Resize the canvas when the layout size changes.\n\t\tuseLayoutEffect(() => {\n\t\t\tresizeCanvas();\n\n\t\t\t// If the parent element is not found or the ResizeObserver is not available, render the frame.\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tconst parent = canvas?.parentElement;\n\t\t\tif (!parent || typeof ResizeObserver === \"undefined\") {\n\t\t\t\trenderFrameRef.current?.();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Create a new ResizeObserver to resize the canvas when the parent element changes size.\n\t\t\tconst observer = new ResizeObserver(() => {\n\t\t\t\tresizeCanvas();\n\t\t\t\trenderFrameRef.current?.();\n\t\t\t});\n\n\t\t\tobserver.observe(parent);\n\t\t\treturn () => observer.disconnect();\n\t\t}, [resizeCanvas]);\n\n\t\t// Render the frame when the canvas is resized.\n\t\tuseEffect(() => {\n\t\t\tlet animationFrameId = 0;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tconst ctx = canvas?.getContext(\"2d\");\n\t\t\tif (!canvas || !ctx) return;\n\n\t\t\tgradientCacheRef.current.clear();\n\n\t\t\t// Determine if the animation should run based on the paused state, document visibility, and reduced motion query.\n\t\t\tconst reducedMotionQuery =\n\t\t\t\tglobalThis.window !== undefined && respectReducedMotion\n\t\t\t\t\t? globalThis.window.matchMedia(\"(prefers-reduced-motion: reduce)\")\n\t\t\t\t\t: null;\n\n\t\t\tconst shouldAnimate = () => {\n\t\t\t\tif (paused) return false;\n\t\t\t\tif (typeof document !== \"undefined\" && document.hidden) return false;\n\t\t\t\tif (reducedMotionQuery?.matches) return false;\n\t\t\t\treturn true;\n\t\t\t};\n\n\t\t\tconst renderFrame = () => {\n\t\t\t\tconst timestamp = Date.now();\n\t\t\t\tconst time = timestamp * waveConfig.timeScale;\n\n\t\t\t\t// Smoothly approach the latest target amplitude from props/intensity.\n\t\t\t\tamplitudeRef.current +=\n\t\t\t\t\twaveConfig.smoothing *\n\t\t\t\t\t(targetAmplitudeRef.current - amplitudeRef.current);\n\n\t\t\t\t// Calculate the oscillating amplitude based on the time and the amplitude oscillation configuration.\n\t\t\t\tconst oscillatingAmplitude =\n\t\t\t\t\twaveConfig.amplitudeOscillation === 0\n\t\t\t\t\t\t? amplitudeRef.current\n\t\t\t\t\t\t: amplitudeRef.current *\n\t\t\t\t\t\t\t(1 + Math.sin(time) * waveConfig.amplitudeOscillation);\n\n\t\t\t\tctx.clearRect(\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tlayoutSizeRef.current.width,\n\t\t\t\t\tlayoutSizeRef.current.height,\n\t\t\t\t);\n\n\t\t\t\tdrawWaveLayers({\n\t\t\t\t\tctx,\n\t\t\t\t\tcolors,\n\t\t\t\t\tconfig: waveConfig,\n\t\t\t\t\tgradientCache: gradientCacheRef.current,\n\t\t\t\t\tlayoutWidth: layoutSizeRef.current.width,\n\t\t\t\t\tlayoutHeight: layoutSizeRef.current.height,\n\t\t\t\t\toscillatingAmplitude,\n\t\t\t\t\ttimestamp,\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst animate = () => {\n\t\t\t\tif (!shouldAnimate()) return;\n\n\t\t\t\trenderFrame();\n\t\t\t\tanimationFrameId = requestAnimationFrame(animate);\n\t\t\t};\n\n\t\t\t// Set the render frame reference to the render frame function.\n\t\t\trenderFrameRef.current = renderFrame;\n\t\t\tresizeCanvas();\n\t\t\trenderFrame();\n\n\t\t\t// Start the animation if the animation should run.\n\t\t\tif (shouldAnimate()) animationFrameId = requestAnimationFrame(animate);\n\n\t\t\tconst handleVisibilityChange = () => {\n\t\t\t\tif (!document.hidden && shouldAnimate()) {\n\t\t\t\t\trenderFrame();\n\t\t\t\t\tanimationFrameId = requestAnimationFrame(animate);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst handleReducedMotionChange = () => {\n\t\t\t\tif (shouldAnimate()) {\n\t\t\t\t\trenderFrame();\n\t\t\t\t\tanimationFrameId = requestAnimationFrame(animate);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tdocument.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\t\t\treducedMotionQuery?.addEventListener(\"change\", handleReducedMotionChange);\n\n\t\t\treturn () => {\n\t\t\t\trenderFrameRef.current = null;\n\t\t\t\tcancelAnimationFrame(animationFrameId);\n\t\t\t\tdocument.removeEventListener(\n\t\t\t\t\t\"visibilitychange\",\n\t\t\t\t\thandleVisibilityChange,\n\t\t\t\t);\n\t\t\t\treducedMotionQuery?.removeEventListener(\n\t\t\t\t\t\"change\",\n\t\t\t\t\thandleReducedMotionChange,\n\t\t\t\t);\n\t\t\t};\n\t\t}, [colors, paused, respectReducedMotion, resizeCanvas, waveConfig]);\n\n\t\treturn (\n\t\t\t<canvas\n\t\t\t\tref={canvasRef}\n\t\t\t\taria-hidden={props[\"aria-hidden\"] ?? true}\n\t\t\t\twidth=\"100%\"\n\t\t\t\theight=\"auto\"\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\n\nWavesComponent.displayName = \"Waves\";\n\nexport const Waves = memo(WavesComponent);\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-animated-waves",
|
|
3
3
|
"description": "Canvas-based animated waves for ReactJS",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"license": "MIT",
|
|
@@ -16,36 +16,53 @@
|
|
|
16
16
|
"module": "./dist/index.js",
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@
|
|
20
|
-
"tailwindcss": "^4.1.18"
|
|
19
|
+
"@ctrl/tinycolor": "^4.2.0"
|
|
21
20
|
},
|
|
22
21
|
"peerDependencies": {
|
|
23
22
|
"react": "^19.1.0",
|
|
24
23
|
"react-dom": "^19.1.0"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
|
-
"@
|
|
28
|
-
"@
|
|
29
|
-
"@commitlint/
|
|
26
|
+
"@tailwindcss/vite": "^4.2.2",
|
|
27
|
+
"@biomejs/biome": "2.4.16",
|
|
28
|
+
"@commitlint/cli": "^21.0.1",
|
|
29
|
+
"@commitlint/config-conventional": "^21.0.1",
|
|
30
30
|
"@fontsource/geist-sans": "^5.2.5",
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
"@
|
|
31
|
+
"@radix-ui/react-collapsible": "^1.1.13",
|
|
32
|
+
"@radix-ui/react-label": "^2.1.9",
|
|
33
|
+
"@radix-ui/react-popover": "^1.1.16",
|
|
34
|
+
"@radix-ui/react-scroll-area": "^1.2.11",
|
|
35
|
+
"@radix-ui/react-select": "^2.3.0",
|
|
36
|
+
"@radix-ui/react-separator": "^1.1.9",
|
|
37
|
+
"@radix-ui/react-slider": "^1.4.0",
|
|
38
|
+
"@radix-ui/react-slot": "^1.2.5",
|
|
39
|
+
"@radix-ui/react-switch": "^1.3.0",
|
|
40
|
+
"@radix-ui/react-tabs": "^1.1.14",
|
|
41
|
+
"@stryker-mutator/core": "^9.6.1",
|
|
42
|
+
"@stryker-mutator/typescript-checker": "^9.6.1",
|
|
43
|
+
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
34
44
|
"@testing-library/jest-dom": "^6.6.3",
|
|
35
45
|
"@testing-library/react": "^16.3.2",
|
|
36
|
-
"@types/node": "^25.
|
|
37
|
-
"@types/react": "^19.2.
|
|
46
|
+
"@types/node": "^25.9.1",
|
|
47
|
+
"@types/react": "^19.2.15",
|
|
48
|
+
"@types/react-color": "^3.0.13",
|
|
38
49
|
"@types/react-dom": "^19.1.4",
|
|
39
|
-
"@vitejs/plugin-react": "^
|
|
40
|
-
"@vitest/coverage-v8": "4.
|
|
41
|
-
"
|
|
42
|
-
"
|
|
50
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
51
|
+
"@vitest/coverage-v8": "4.1.7",
|
|
52
|
+
"class-variance-authority": "^0.7.1",
|
|
53
|
+
"clsx": "^2.1.1",
|
|
54
|
+
"git-cliff": "^2.13.1",
|
|
55
|
+
"happy-dom": "^20.9.0",
|
|
43
56
|
"husky": "^9.1.7",
|
|
44
|
-
"lint-staged": "^
|
|
45
|
-
"
|
|
57
|
+
"lint-staged": "^17.0.5",
|
|
58
|
+
"lucide-react": "^1.17.0",
|
|
59
|
+
"react-color": "^2.19.3",
|
|
60
|
+
"tailwind-merge": "^3.6.0",
|
|
61
|
+
"tailwindcss": "^4.2.2",
|
|
62
|
+
"tsdown": "^0.22.0",
|
|
46
63
|
"typescript": "^5.9.2",
|
|
47
|
-
"vite": "^
|
|
48
|
-
"vitest": "^4.
|
|
64
|
+
"vite": "^8.0.14",
|
|
65
|
+
"vitest": "^4.1.7"
|
|
49
66
|
},
|
|
50
67
|
"scripts": {
|
|
51
68
|
"build": "tsdown",
|