UNPKG

ngx-audio-wave

Version:

A modern, accessible audio wave visualization component for Angular 22+ with comprehensive keyboard navigation and screen reader support.

316 lines (244 loc) â€ĸ 13 kB
# ngx-audio-wave A modern, accessible audio wave visualization component for Angular 22+ with comprehensive keyboard navigation and screen reader support. ## Features - đŸŽĩ **Audio Wave Visualization** - Beautiful SVG-based audio wave display - âŒ¨ī¸ **Full Keyboard Support** - Complete keyboard navigation (Space, Enter, Arrow keys, Home, End) - â™ŋ **Accessibility First** - WCAG 2.1 compliant with ARIA support - 🎨 **Highly Customizable** - Colors, dimensions, gaps, and styling options - 📱 **Responsive Design** - Works on all screen sizes - 🚀 **Modern Angular** - Built with Angular 22+ signals and standalone components - đŸŽ¯ **TypeScript** - Full type safety and IntelliSense support ## Demo **🎮 [Live Demo](https://joldibaev.github.io/ngx-audio-wave/)** - Try the interactive demo ![Audio Wave Demo](https://github.com/joldibaev/ngx-audio-wave/raw/master/public/demo3.png) ## Quick Start ### Installation ```bash npm install ngx-audio-wave ``` ### Angular 22+ (Standalone Components) ```ts import { NgxAudioWave } from 'ngx-audio-wave'; @Component({ selector: 'app-root', standalone: true, imports: [NgxAudioWave], template: ` <ngx-audio-wave ariaLabel="My audio player" audioSrc="path/to/your/audio.mp3" > </ngx-audio-wave> `, }) export class AppComponent {} ``` If your app does not already provide Angular HTTP services, add `provideHttpClient()` to your app config. Remote audio files must allow browser CORS access because the component downloads the file to generate waveform data. ## Basic Usage ```html <ngx-audio-wave ariaLabel="My podcast episode" audioSrc="https://example.com/audio.mp3" > </ngx-audio-wave> ``` ### With Progress Information ```html <ngx-audio-wave #player audioSrc="assets/audio.mp3"></ngx-audio-wave> <div class="audio-info"> <p>Progress: {{ player.exactPlayedPercent() | number:'1.1-1' }}%</p> <p> Time: {{ player.exactCurrentTime() | number:'1.1-1' }}s / {{ player.exactDuration() | number:'1.1-1' }}s </p> <p>Status: {{ player.statusText() }}</p> </div> ``` ## Examples ### Custom Styling ```html <ngx-audio-wave [gap]="3" [height]="50" [rounded]="false" audioSrc="assets/audio.mp3" color="#ff6b6b" > </ngx-audio-wave> ``` ### With Custom Accessibility Labels ```html <ngx-audio-wave ariaLabel="Weekly Tech Podcast Episode 42" audioSrc="assets/podcast.mp3" pauseButtonLabel="Pause podcast" playButtonLabel="Start podcast" progressBarLabel="Podcast progress - use arrow keys to navigate" > </ngx-audio-wave> ``` ### Hide Default Button ```html <ngx-audio-wave [hideBtn]="true" #audioPlayer audioSrc="assets/audio.mp3"> </ngx-audio-wave> <button (click)="audioPlayer.play()">â–ļī¸ Play</button> <button (click)="audioPlayer.pause()">â¸ī¸ Pause</button> <button (click)="audioPlayer.stop()">âšī¸ Stop</button> ``` ### Volume Control ```html <ngx-audio-wave #player audioSrc="assets/audio.mp3"></ngx-audio-wave> <div class="volume-controls"> <button (click)="player.setVolume(0)">🔇 Mute</button> <button (click)="player.setVolume(0.5)">50% Volume</button> <button (click)="player.setVolume(1)">100% Volume</button> <button (click)="player.setVolume(player.currentVolume() === 0 ? 1 : 0)"> Toggle </button> </div> <p>Current volume: {{ player.currentVolume() | percent }}</p> ``` ### Playback Speed Control ```html <ngx-audio-wave #player audioSrc="assets/audio.mp3"></ngx-audio-wave> <div class="speed-controls"> <button (click)="player.setPlaybackRate(player.currentPlaybackRate() - 0.25)"> âĒ Slower </button> <button (click)="player.setPlaybackRate(1)">1x Normal</button> <button (click)="player.setPlaybackRate(player.currentPlaybackRate() + 0.25)"> ⏊ Faster </button> <button (click)="player.setPlaybackRate(0.5)">0.5x</button> <button (click)="player.setPlaybackRate(1.5)">1.5x</button> <button (click)="player.setPlaybackRate(2)">2x</button> </div> <p>Current speed: {{ player.currentPlaybackRate() }}x</p> ``` ### Loop Control ```html <ngx-audio-wave #player audioSrc="assets/audio.mp3"></ngx-audio-wave> <div class="loop-controls"> <button (click)="player.setLoop(true)">🔄 Enable Loop</button> <button (click)="player.setLoop(false)">âšī¸ Disable Loop</button> <button (click)="player.setLoop(!player.isLooping())"> 🔄/âšī¸ Toggle Loop </button> </div> <p>Looping: {{ player.isLooping() ? 'Enabled' : 'Disabled' }}</p> <!-- Auto-loop example --> <ngx-audio-wave [loop]="true" ariaLabel="Background music with auto-loop" audioSrc="assets/background-music.mp3" > </ngx-audio-wave> ``` ### Different Heights and Gaps ```html <!-- Different heights --> <ngx-audio-wave [height]="25" audioSrc="assets/audio.mp3"></ngx-audio-wave> <ngx-audio-wave [height]="50" audioSrc="assets/audio.mp3"></ngx-audio-wave> <ngx-audio-wave [height]="100" audioSrc="assets/audio.mp3"></ngx-audio-wave> <!-- Different gaps --> <ngx-audio-wave [gap]="1" audioSrc="assets/audio.mp3"></ngx-audio-wave> <ngx-audio-wave [gap]="5" audioSrc="assets/audio.mp3"></ngx-audio-wave> <ngx-audio-wave [gap]="10" audioSrc="assets/audio.mp3"></ngx-audio-wave> ``` ## Accessibility Features This component is built with accessibility as a core feature, ensuring it works seamlessly with assistive technologies and keyboard navigation. ### Keyboard Navigation | Key | Action | | ------------------ | ---------------------------------------- | | `Space` or `Enter` | Play/Pause audio | | `Arrow Left` | Skip backward (configurable with `skip`) | | `Arrow Right` | Skip forward (configurable with `skip`) | | `Home` | Jump to beginning | | `End` | Jump to end | ### Screen Reader Support - **ARIA Labels**: All interactive elements have descriptive labels - **Live Regions**: Status changes are announced automatically - **Progress Information**: Detailed progress text with time and percentage - **Semantic Roles**: Proper ARIA roles for all components - **Focus Management**: Logical tab order and focus indicators ### Screen Reader Testing Recommended manual test matrix before release: - **NVDA** (Windows) - **JAWS** (Windows) - **VoiceOver** (macOS/iOS) - **TalkBack** (Android) ## API Reference ### Input Properties | Property | Type | Default | Description | | ------------------ | ------------------- | ---------------------- | ------------------------------------------ | | `audioSrc` | `string \| SafeUrl` | **Required** | URL or SafeUrl of the audio file to play | | `color` | `string` | `'#1e90ff'` | Color of the audio wave bars | | `height` | `number` | `25` | Height of the wave visualization in pixels | | `gap` | `number` | `5` | Gap between wave bars in pixels | | `samples` | `number` | `50` | Number of waveform bars | | `rounded` | `boolean` | `true` | Whether to round the corners of wave bars | | `hideBtn` | `boolean` | `false` | Hide the play/pause button | | `skip` | `number` | `5` | Seconds to skip when using arrow keys | | `volume` | `number` | `1` | Initial volume level (0-1) | | `playbackRate` | `number` | `1` | Initial playback speed (0.25-4) | | `loop` | `boolean` | `false` | Whether to loop the audio | | `ariaLabel` | `string` | `'Audio player'` | Main ARIA label for the component | | `playButtonLabel` | `string` | `'Play audio'` | ARIA label for the play button | | `pauseButtonLabel` | `string` | `'Pause audio'` | ARIA label for the pause button | | `progressBarLabel` | `string` | `'Audio progress bar'` | ARIA label for the progress bar | ### Output Properties (Signals) | Property | Type | Description | | --------------------- | ----------------- | ----------------------------------------------- | | `isPaused` | `Signal<boolean>` | Whether the audio is currently paused | | `isLoading` | `Signal<boolean>` | Whether the audio is currently loading | | `hasError` | `Signal<boolean>` | Whether there was an error loading the audio | | `currentVolume` | `Signal<number>` | Current volume level (0-1) | | `currentPlaybackRate` | `Signal<number>` | Current playback speed (0.25-4) | | `isLooping` | `Signal<boolean>` | Whether the audio is currently looping | | `exactCurrentTime` | `Signal<number>` | Current playback time in seconds (exact) | | `exactDuration` | `Signal<number>` | Total duration in seconds (exact) | | `exactPlayedPercent` | `Signal<number>` | Playback progress as percentage (exact) | | `progressText` | `Signal<string>` | Human-readable progress text for screen readers | | `statusText` | `Signal<string>` | Current status text for screen readers | ### Methods | Method | Parameters | Description | | ------------------------ | ---------------- | -------------------------------------------------------------------- | | `play(time?: number)` | `time?: number` | Play the audio, optionally from a specific time | | `pause()` | - | Pause the audio | | `stop()` | - | Stop the audio and reset to beginning | | `setVolume(volume)` | `volume: number` | Set volume level (0-1) | | `mute()` | - | **Deprecated** - Use `setVolume(0)` | | `unmute()` | - | **Deprecated** - Use `setVolume(value)` | | `toggleMute()` | - | **Deprecated** - Use `setVolume(currentVolume() === 0 ? value : 0)` | | `setPlaybackRate(rate)` | `rate: number` | Set playback speed (0.25-4) | | `resetPlaybackRate()` | - | **Deprecated** - Use `setPlaybackRate(1)` | | `increasePlaybackRate()` | - | **Deprecated** - Use `setPlaybackRate(currentPlaybackRate() + 0.25)` | | `decreasePlaybackRate()` | - | **Deprecated** - Use `setPlaybackRate(currentPlaybackRate() - 0.25)` | | `setLoop(loop)` | `loop: boolean` | Enable or disable audio looping | | `enableLoop()` | - | **Deprecated** - Use `setLoop(true)` | | `disableLoop()` | - | **Deprecated** - Use `setLoop(false)` | | `toggleLoop()` | - | **Deprecated** - Use `setLoop(!isLooping())` | ## Breaking Changes in v22 - Removed deprecated rounded state aliases: `currentTime`, `duration`, and `playedPercent`. - Use `exactCurrentTime`, `exactDuration`, and `exactPlayedPercent` instead. - Deprecated convenience methods remain available in v22 and are scheduled for removal in v23: `mute()`, `unmute()`, `toggleMute()`, `resetPlaybackRate()`, `increasePlaybackRate()`, `decreasePlaybackRate()`, `enableLoop()`, `disableLoop()`, and `toggleLoop()`. ## Compatibility Notes - Angular: `>=22.0.0 <23.0.0` - Node.js: `^22.22.3 || ^24.15.0 || >=26.0.0` - `provideHttpClient()` is required by the current waveform loader. - Large audio files are downloaded and decoded in the browser for waveform generation. Prefer smaller preview files for long podcasts or many players on one page. ## Contributing We welcome contributions! Please feel free to submit issues and pull requests. ## License MIT License - see [LICENSE](LICENSE) file for details. ## Support - 📧 Email: nurlan@joldibaev.uz - 🐛 Issues: [GitHub Issues](https://github.com/joldibaev/ngx-audio-wave/issues) - đŸ’Ŧ Discussions: [GitHub Discussions](https://github.com/joldibaev/ngx-audio-wave/discussions) --- **Made with â¤ī¸ by [Joldibaev Nurlan](https://github.com/joldibaev)**