snice 3.6.0 → 3.8.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.
Files changed (80) hide show
  1. package/README.md +2 -2
  2. package/bin/snice.js +4 -5
  3. package/bin/templates/CLAUDE.md +25 -3
  4. package/bin/templates/pwa/README.md +188 -0
  5. package/bin/templates/pwa/global.d.ts +10 -0
  6. package/bin/templates/pwa/index.html +16 -0
  7. package/bin/templates/pwa/package.json +32 -0
  8. package/bin/templates/pwa/public/icons/.gitkeep +6 -0
  9. package/bin/templates/pwa/src/daemons/notifications.ts +148 -0
  10. package/bin/templates/pwa/src/fetcher.ts +15 -0
  11. package/bin/templates/pwa/src/guards/auth.ts +12 -0
  12. package/bin/templates/pwa/src/main.ts +42 -0
  13. package/bin/templates/pwa/src/middleware/auth.ts +16 -0
  14. package/bin/templates/pwa/src/middleware/error.ts +36 -0
  15. package/bin/templates/pwa/src/middleware/retry.ts +31 -0
  16. package/bin/templates/pwa/src/pages/dashboard.ts +143 -0
  17. package/bin/templates/pwa/src/pages/login.ts +161 -0
  18. package/bin/templates/pwa/src/pages/notifications.ts +156 -0
  19. package/bin/templates/pwa/src/pages/profile.ts +164 -0
  20. package/bin/templates/pwa/src/router.ts +20 -0
  21. package/bin/templates/pwa/src/services/auth.ts +48 -0
  22. package/bin/templates/pwa/src/services/jwt.ts +35 -0
  23. package/bin/templates/pwa/src/services/storage.ts +24 -0
  24. package/bin/templates/pwa/src/styles/global.css +55 -0
  25. package/bin/templates/pwa/src/types/auth.ts +21 -0
  26. package/bin/templates/pwa/src/types/notifications.ts +9 -0
  27. package/bin/templates/pwa/tests/helpers/test-utils.ts +84 -0
  28. package/bin/templates/pwa/tests/middleware/auth.test.ts +67 -0
  29. package/bin/templates/pwa/tests/middleware/error.test.ts +105 -0
  30. package/bin/templates/pwa/tests/middleware/retry.test.ts +103 -0
  31. package/bin/templates/pwa/tests/services/auth.test.ts +89 -0
  32. package/bin/templates/pwa/tests/services/jwt.test.ts +76 -0
  33. package/bin/templates/pwa/tests/services/storage.test.ts +69 -0
  34. package/bin/templates/{social → pwa}/tsconfig.json +11 -10
  35. package/bin/templates/pwa/vite.config.ts +94 -0
  36. package/bin/templates/{social/vite.config.ts → pwa/vitest.config.ts} +12 -17
  37. package/dist/components/music-player/snice-music-player.d.ts +72 -0
  38. package/dist/components/music-player/snice-music-player.js +730 -0
  39. package/dist/components/music-player/snice-music-player.js.map +1 -0
  40. package/dist/components/music-player/snice-music-player.types.d.ts +43 -0
  41. package/dist/components/timer/snice-timer.d.ts +27 -0
  42. package/dist/components/timer/snice-timer.js +197 -0
  43. package/dist/components/timer/snice-timer.js.map +1 -0
  44. package/dist/components/timer/snice-timer.types.d.ts +10 -0
  45. package/dist/fetcher.d.ts +65 -0
  46. package/dist/index.cjs +92 -3
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.ts +2 -0
  49. package/dist/index.esm.js +92 -4
  50. package/dist/index.esm.js.map +1 -1
  51. package/dist/index.iife.js +92 -3
  52. package/dist/index.iife.js.map +1 -1
  53. package/dist/symbols.cjs +1 -1
  54. package/dist/symbols.esm.js +1 -1
  55. package/dist/transitions.cjs +1 -1
  56. package/dist/transitions.esm.js +1 -1
  57. package/dist/types/context.d.ts +7 -1
  58. package/dist/types/router-options.d.ts +6 -0
  59. package/docs/ai/api.md +33 -1
  60. package/docs/ai/components/music-player.md +134 -0
  61. package/docs/ai/components/timer.md +43 -0
  62. package/docs/ai/patterns.md +48 -1
  63. package/docs/components/music-player.md +314 -0
  64. package/docs/components/timer.md +143 -0
  65. package/docs/fetcher.md +447 -0
  66. package/docs/routing.md +11 -8
  67. package/package.json +2 -1
  68. package/bin/templates/social/README.md +0 -42
  69. package/bin/templates/social/global.d.ts +0 -14
  70. package/bin/templates/social/index.html +0 -13
  71. package/bin/templates/social/package.json +0 -21
  72. package/bin/templates/social/src/main.ts +0 -33
  73. package/bin/templates/social/src/pages/feed-page.ts +0 -111
  74. package/bin/templates/social/src/pages/messages-page.ts +0 -102
  75. package/bin/templates/social/src/pages/not-found-page.ts +0 -46
  76. package/bin/templates/social/src/pages/profile-page.ts +0 -99
  77. package/bin/templates/social/src/pages/settings-page.ts +0 -119
  78. package/bin/templates/social/src/router.ts +0 -9
  79. package/bin/templates/social/src/styles/global.css +0 -156
  80. /package/bin/templates/{social → pwa}/public/vite.svg +0 -0
package/dist/symbols.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v3.5.0
2
+ * snice v3.7.0
3
3
  * Imperative TypeScript framework for building vanilla web components with decorators, differential rendering, routing, and controllers. No virtual DOM, no build complexity.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v3.5.0
2
+ * snice v3.7.0
3
3
  * Imperative TypeScript framework for building vanilla web components with decorators, differential rendering, routing, and controllers. No virtual DOM, no build complexity.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v3.5.0
2
+ * snice v3.7.0
3
3
  * Imperative TypeScript framework for building vanilla web components with decorators, differential rendering, routing, and controllers. No virtual DOM, no build complexity.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v3.5.0
2
+ * snice v3.7.0
3
3
  * Imperative TypeScript framework for building vanilla web components with decorators, differential rendering, routing, and controllers. No virtual DOM, no build complexity.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -3,6 +3,7 @@ import { NavContext } from './nav-context';
3
3
  import { Placard } from './placard';
4
4
  import { RouteParams } from './route-params';
5
5
  import { REGISTERED_ELEMENTS, IS_UPDATING, CONTEXT_REGISTER, CONTEXT_UNREGISTER, CONTEXT_NOTIFY_ELEMENT } from '../symbols';
6
+ import type { Fetcher } from '../fetcher';
6
7
  declare const REGISTERED_ELEMENTS_SET: unique symbol;
7
8
  /**
8
9
  * Represents the bundled router state that can notify registered elements of changes
@@ -38,7 +39,12 @@ export declare class Context {
38
39
  * Navigation state
39
40
  */
40
41
  navigation: NavContext;
41
- constructor(context?: AppContext, placards?: Placard[], currentRoute?: string, routeParams?: RouteParams);
42
+ /**
43
+ * Fetch function with optional middleware support
44
+ * Bound to this Context instance, allowing middleware to access application and navigation state
45
+ */
46
+ fetch: typeof globalThis.fetch;
47
+ constructor(context?: AppContext, placards?: Placard[], currentRoute?: string, routeParams?: RouteParams, fetcher?: Fetcher);
42
48
  /**
43
49
  * Update the context and notify all registered elements
44
50
  * Prevents infinite loops by tracking update state
@@ -1,4 +1,5 @@
1
1
  import { Transition } from './transition';
2
+ import type { Fetcher } from '../fetcher';
2
3
  export interface RouterOptions {
3
4
  /**
4
5
  * The target element selector where the page element will be instantiated.
@@ -29,4 +30,9 @@ export interface RouterOptions {
29
30
  * Default layout element tag name for all pages
30
31
  */
31
32
  layout?: string;
33
+ /**
34
+ * Optional fetcher for context-aware HTTP requests with middleware support
35
+ * If not provided, Context.fetch will default to native fetch
36
+ */
37
+ fetcher?: Fetcher;
32
38
  }
package/docs/ai/api.md CHANGED
@@ -147,13 +147,45 @@ html`
147
147
  // ctx.update(); // notify all subscribers
148
148
  // }
149
149
 
150
- Router({ target, context?, layout? })
150
+ Router({ target, context?, layout?, fetcher? })
151
151
  // Returns: { page, navigate, initialize }
152
152
  // page() - decorator factory
153
153
  // navigate(path) - programmatic navigation
154
154
  // initialize() - start router
155
155
  ```
156
156
 
157
+ ## Fetcher
158
+
159
+ ```typescript
160
+ class ContextAwareFetcher implements Fetcher {
161
+ use(type: 'request', middleware: RequestMiddleware): void
162
+ use(type: 'response', middleware: ResponseMiddleware): void
163
+ create(ctx: Context): typeof globalThis.fetch
164
+ }
165
+
166
+ type RequestMiddleware = (
167
+ this: Context,
168
+ request: Request,
169
+ next: () => Promise<Response>
170
+ ) => Promise<Response>
171
+
172
+ type ResponseMiddleware = (
173
+ this: Context,
174
+ response: Response,
175
+ next: () => Promise<Response>
176
+ ) => Promise<Response>
177
+ ```
178
+
179
+ **Usage:**
180
+ - Create fetcher, add middleware via `.use('request', fn)` and `.use('response', fn)`
181
+ - Request middleware runs before fetch, response middleware after
182
+ - Middleware `this` bound to Context instance
183
+ - Access `this.application` and `this.navigation` in middleware
184
+ - Pass to Router via `fetcher` option
185
+ - Use via `ctx.fetch()` in pages/components
186
+ - Optional - defaults to native fetch if not provided
187
+ ```
188
+
157
189
  ## Templates
158
190
 
159
191
  ```typescript
@@ -0,0 +1,134 @@
1
+ # snice-music-player
2
+
3
+ Full-featured audio player with playlist, shuffle, repeat, and volume control.
4
+
5
+ ## Properties
6
+
7
+ ```typescript
8
+ tracks: Track[] = [];
9
+ currentTrackIndex: number = 0;
10
+ currentTrack: string = ''; // reflected attribute
11
+ currentTime: number = 0; // read-only, use seek()
12
+ duration: number = 0;
13
+ volume: number = 1;
14
+ muted: boolean = false;
15
+ shuffle: boolean = false;
16
+ repeat: 'off'|'all'|'one' = 'off';
17
+ state: 'playing'|'paused'|'stopped'|'loading'|'error' = 'stopped';
18
+ autoplay: boolean = false;
19
+ showPlaylist: boolean = true;
20
+ showControls: boolean = true;
21
+ showVolume: boolean = true;
22
+ showArtwork: boolean = true;
23
+ showTrackInfo: boolean = true;
24
+ compact: boolean = false;
25
+ ```
26
+
27
+ ## Methods
28
+
29
+ ```typescript
30
+ play(): Promise<void>
31
+ pause(): void
32
+ stop(): void
33
+ next(): void
34
+ previous(): void
35
+ seek(time: number): void
36
+ setVolume(volume: number): void
37
+ toggleShuffle(): void
38
+ setRepeat(mode: 'off'|'all'|'one'): void
39
+ loadTrack(index: number): Promise<void>
40
+ getCurrentTrack(): Track | null
41
+ ```
42
+
43
+ ## Track Interface
44
+
45
+ ```typescript
46
+ interface Track {
47
+ id: string;
48
+ title: string;
49
+ artist?: string;
50
+ album?: string;
51
+ artwork?: string;
52
+ src: string;
53
+ duration?: number;
54
+ }
55
+ ```
56
+
57
+ ## Events
58
+
59
+ - `@snice/player-play` - Playback started
60
+ - `@snice/player-pause` - Playback paused
61
+ - `@snice/player-stop` - Playback stopped
62
+ - `@snice/player-track-change` - Track changed
63
+ - `@snice/player-track-ended` - Track ended
64
+ - `@snice/player-shuffle-change` - Shuffle changed
65
+ - `@snice/player-repeat-change` - Repeat mode changed
66
+ - `@snice/player-volume-change` - Volume changed
67
+ - `@snice/player-time-update` - Time updated
68
+ - `@snice/player-error` - Error occurred
69
+
70
+ ## Usage
71
+
72
+ ```javascript
73
+ // Set tracks
74
+ player.tracks = [
75
+ {
76
+ id: '1',
77
+ title: 'Song Title',
78
+ artist: 'Artist Name',
79
+ album: 'Album Name',
80
+ artwork: 'https://example.com/art.jpg',
81
+ src: 'https://example.com/audio.mp3',
82
+ duration: 180
83
+ }
84
+ ];
85
+
86
+ // Controls
87
+ await player.play();
88
+ player.pause();
89
+ player.stop();
90
+ player.next();
91
+ player.previous();
92
+ player.seek(30);
93
+
94
+ // Volume
95
+ player.setVolume(0.5);
96
+
97
+ // Shuffle & repeat
98
+ player.toggleShuffle();
99
+ player.setRepeat('all');
100
+
101
+ // Load track
102
+ await player.loadTrack(2);
103
+
104
+ // Get current
105
+ const track = player.getCurrentTrack();
106
+
107
+ // Get/set via currentTrack attribute
108
+ console.log(player.currentTrack); // track ID
109
+ player.currentTrack = 'track-2'; // loads track by ID
110
+ ```
111
+
112
+ ```html
113
+ <snice-music-player
114
+ autoplay
115
+ shuffle
116
+ compact
117
+ show-playlist="false">
118
+ </snice-music-player>
119
+ ```
120
+
121
+ ## Features
122
+
123
+ - HTML5 Audio API
124
+ - Playlist support
125
+ - Play/pause/stop/next/previous
126
+ - Shuffle with randomization
127
+ - Repeat modes: off, all, one
128
+ - Volume control (vertical slider)
129
+ - Progress bar with seek
130
+ - Real-time updates
131
+ - Track artwork & metadata
132
+ - Compact mode
133
+ - Event-driven
134
+ - Clickable playlist
@@ -0,0 +1,43 @@
1
+ # Timer
2
+
3
+ ```html
4
+ <snice-timer mode="stopwatch"></snice-timer>
5
+ <snice-timer mode="timer" initial-time="60"></snice-timer>
6
+ ```
7
+
8
+ ## Properties
9
+ - `mode`: 'stopwatch' | 'timer' (default: 'stopwatch')
10
+ - `initial-time`: number (default: 0) - Starting time in seconds for timer mode
11
+ - `running`: boolean (read-only)
12
+
13
+ ## Methods
14
+ - `start()`: Start timer
15
+ - `stop()`: Stop/pause timer
16
+ - `reset()`: Reset to initial state
17
+ - `getTime()`: Get current time in seconds
18
+
19
+ ## Events
20
+ - `@snice/timer-start`: { timer, time }
21
+ - `@snice/timer-stop`: { timer, time }
22
+ - `@snice/timer-reset`: { timer, time }
23
+ - `@snice/timer-complete`: { timer } - Countdown reached 0
24
+
25
+ ## Implementation
26
+ - Uses requestAnimationFrame for smooth updates
27
+ - Direct DOM manipulation for display to avoid re-renders
28
+ - Stopwatch: counts up from 0
29
+ - Timer: counts down from initial-time
30
+ - Auto-stops at 0 in timer mode
31
+
32
+ ## Display Format
33
+ - Under 1 hour: `M:SS.D` (e.g., "2:05.3")
34
+ - Over 1 hour: `H:MM:SS` (e.g., "1:05:30")
35
+
36
+ ## Theme Integration
37
+ Uses standard theme tokens:
38
+ - Background: `--snice-color-background-element`
39
+ - Borders: `--snice-color-border`
40
+ - Text: `--snice-color-text`
41
+ - Start button: `--snice-color-success`
42
+ - Pause button: `--snice-color-warning`
43
+ - Reset button: `--snice-color-neutral`
@@ -56,7 +56,7 @@ class UserPage extends HTMLElement {
56
56
  private appContext?: AppContext;
57
57
 
58
58
  @context()
59
- handleContext(ctx: Context<AppContext>) {
59
+ handleContext(ctx: Context) {
60
60
  this.appContext = ctx.application;
61
61
  this.requestRender();
62
62
  }
@@ -115,6 +115,53 @@ class UserProfile extends HTMLElement {
115
115
  }
116
116
  ```
117
117
 
118
+ ## Fetch with Middleware
119
+
120
+ ```typescript
121
+ import { Router, ContextAwareFetcher } from 'snice';
122
+
123
+ const fetcher = new ContextAwareFetcher();
124
+
125
+ // Request middleware - modify request before fetch
126
+ fetcher.use('request', function(request, next) {
127
+ const token = this.application.user?.token;
128
+ if (token) {
129
+ request.headers.set('Authorization', `Bearer ${token}`);
130
+ }
131
+ return next();
132
+ });
133
+
134
+ // Response middleware - handle response after fetch
135
+ fetcher.use('response', async function(response, next) {
136
+ if (!response.ok) {
137
+ throw new Error(`HTTP ${response.status}`);
138
+ }
139
+ return next();
140
+ });
141
+
142
+ const router = Router({
143
+ target: '#app',
144
+ context: { user: null },
145
+ fetcher
146
+ });
147
+
148
+ // In pages
149
+ @page({ tag: 'user-page', routes: ['/users/:id'] })
150
+ class UserPage extends HTMLElement {
151
+ private ctx: Context;
152
+
153
+ @context()
154
+ handleContext(ctx: Context) {
155
+ this.ctx = ctx;
156
+ }
157
+
158
+ @ready()
159
+ async load() {
160
+ const user = await this.ctx.fetch('/api/users/123').then(r => r.json());
161
+ }
162
+ }
163
+ ```
164
+
118
165
  ## Conditional Rendering
119
166
  ```typescript
120
167
  html`
@@ -0,0 +1,314 @@
1
+ # Music Player Component
2
+
3
+ A full-featured audio player with playlist support, shuffle, repeat modes, and volume control.
4
+
5
+ ## Basic Usage
6
+
7
+ ```html
8
+ <snice-music-player id="player"></snice-music-player>
9
+
10
+ <script>
11
+ const player = document.getElementById('player');
12
+
13
+ // Set tracks
14
+ player.tracks = [
15
+ {
16
+ id: 'track-1',
17
+ title: 'Song Title',
18
+ artist: 'Artist Name',
19
+ album: 'Album Name',
20
+ artwork: 'https://example.com/artwork.jpg',
21
+ src: 'https://example.com/audio.mp3',
22
+ duration: 180
23
+ }
24
+ ];
25
+
26
+ // Listen for events
27
+ player.addEventListener('@snice/player-play', (e) => {
28
+ console.log('Playing:', e.detail.track.title);
29
+ });
30
+ </script>
31
+ ```
32
+
33
+ ## Properties
34
+
35
+ | Property | Type | Default | Description |
36
+ |----------|------|---------|-------------|
37
+ | `tracks` | `Track[]` | `[]` | Array of tracks |
38
+ | `currentTrackIndex` | `number` | `0` | Current track index |
39
+ | `currentTrack` | `string` | `''` | Current track ID (reflected attribute) |
40
+ | `currentTime` | `number` | `0` | Current playback time (read-only, use seek() to set) |
41
+ | `duration` | `number` | `0` | Track duration (seconds) |
42
+ | `volume` | `number` | `1` | Volume (0-1) |
43
+ | `muted` | `boolean` | `false` | Mute state |
44
+ | `shuffle` | `boolean` | `false` | Shuffle mode |
45
+ | `repeat` | `RepeatMode` | `'off'` | Repeat mode |
46
+ | `state` | `PlayerState` | `'stopped'` | Playback state |
47
+ | `autoplay` | `boolean` | `false` | Auto-play on load |
48
+ | `showPlaylist` | `boolean` | `true` | Show playlist |
49
+ | `showControls` | `boolean` | `true` | Show control buttons |
50
+ | `showVolume` | `boolean` | `true` | Show volume control |
51
+ | `showArtwork` | `boolean` | `true` | Show artwork |
52
+ | `showTrackInfo` | `boolean` | `true` | Show track info |
53
+ | `compact` | `boolean` | `false` | Compact mode |
54
+
55
+ ## Track Interface
56
+
57
+ ```typescript
58
+ interface Track {
59
+ id: string;
60
+ title: string;
61
+ artist?: string;
62
+ album?: string;
63
+ artwork?: string;
64
+ src: string;
65
+ duration?: number;
66
+ }
67
+ ```
68
+
69
+ ## Repeat Modes
70
+
71
+ - `'off'` - No repeat
72
+ - `'all'` - Repeat all tracks
73
+ - `'one'` - Repeat current track
74
+
75
+ ## Player States
76
+
77
+ - `'playing'` - Currently playing
78
+ - `'paused'` - Paused
79
+ - `'stopped'` - Stopped
80
+ - `'loading'` - Loading track
81
+ - `'error'` - Error occurred
82
+
83
+ ## Methods
84
+
85
+ ### `play(): Promise<void>`
86
+ Start or resume playback.
87
+
88
+ ### `pause(): void`
89
+ Pause playback.
90
+
91
+ ### `stop(): void`
92
+ Stop playback and reset position.
93
+
94
+ ### `next(): void`
95
+ Skip to next track.
96
+
97
+ ### `previous(): void`
98
+ Skip to previous track.
99
+
100
+ ### `seek(time: number): void`
101
+ Seek to specific time (seconds).
102
+
103
+ ### `setVolume(volume: number): void`
104
+ Set volume (0-1).
105
+
106
+ ### `toggleShuffle(): void`
107
+ Toggle shuffle mode.
108
+
109
+ ### `setRepeat(mode: RepeatMode): void`
110
+ Set repeat mode.
111
+
112
+ ### `loadTrack(index: number): Promise<void>`
113
+ Load track by index.
114
+
115
+ ### `getCurrentTrack(): Track | null`
116
+ Get current track.
117
+
118
+ ## Events
119
+
120
+ - `@snice/player-play` - Playback started
121
+ - `@snice/player-pause` - Playback paused
122
+ - `@snice/player-stop` - Playback stopped
123
+ - `@snice/player-track-change` - Track changed
124
+ - `@snice/player-track-ended` - Track ended
125
+ - `@snice/player-shuffle-change` - Shuffle changed
126
+ - `@snice/player-repeat-change` - Repeat mode changed
127
+ - `@snice/player-volume-change` - Volume changed
128
+ - `@snice/player-time-update` - Playback time updated
129
+ - `@snice/player-error` - Error occurred
130
+
131
+ ## Examples
132
+
133
+ ### Full Player with Playlist
134
+
135
+ ```html
136
+ <snice-music-player id="player"></snice-music-player>
137
+
138
+ <script>
139
+ const player = document.getElementById('player');
140
+
141
+ player.tracks = [
142
+ {
143
+ id: '1',
144
+ title: 'Summer Breeze',
145
+ artist: 'The Acoustic Collective',
146
+ album: 'Peaceful Moments',
147
+ artwork: 'https://example.com/art1.jpg',
148
+ src: 'https://example.com/track1.mp3',
149
+ duration: 360
150
+ },
151
+ {
152
+ id: '2',
153
+ title: 'Midnight Jazz',
154
+ artist: 'Smooth Notes Ensemble',
155
+ album: 'Late Night Sessions',
156
+ artwork: 'https://example.com/art2.jpg',
157
+ src: 'https://example.com/track2.mp3',
158
+ duration: 420
159
+ }
160
+ ];
161
+ </script>
162
+ ```
163
+
164
+ ### Compact Player (No Playlist)
165
+
166
+ ```html
167
+ <snice-music-player
168
+ show-playlist="false"
169
+ compact>
170
+ </snice-music-player>
171
+ ```
172
+
173
+ ### Minimal Player
174
+
175
+ ```html
176
+ <snice-music-player
177
+ show-playlist="false"
178
+ show-artwork="false"
179
+ show-track-info="false">
180
+ </snice-music-player>
181
+ ```
182
+
183
+ ### Programmatic Control
184
+
185
+ ```javascript
186
+ const player = document.querySelector('snice-music-player');
187
+
188
+ // Play/Pause
189
+ await player.play();
190
+ player.pause();
191
+ player.stop();
192
+
193
+ // Navigation
194
+ player.next();
195
+ player.previous();
196
+
197
+ // Seek
198
+ player.seek(30); // Jump to 30 seconds
199
+
200
+ // Volume
201
+ player.setVolume(0.5); // 50% volume
202
+
203
+ // Shuffle
204
+ player.toggleShuffle();
205
+
206
+ // Repeat
207
+ player.setRepeat('all');
208
+ player.setRepeat('one');
209
+ player.setRepeat('off');
210
+
211
+ // Load track
212
+ await player.loadTrack(2); // Load third track
213
+
214
+ // Get current track
215
+ const track = player.getCurrentTrack();
216
+ console.log(track.title, track.artist);
217
+
218
+ // Get/set via currentTrack attribute
219
+ console.log(player.currentTrack); // Returns track ID
220
+ player.currentTrack = 'track-2'; // Loads track with this ID
221
+
222
+ // Change time via seek (currentTime is read-only)
223
+ player.seek(30); // Jump to 30 seconds
224
+ ```
225
+
226
+ ### Event Handling
227
+
228
+ ```javascript
229
+ const player = document.querySelector('snice-music-player');
230
+
231
+ player.addEventListener('@snice/player-play', (e) => {
232
+ console.log('Playing:', e.detail.track);
233
+ });
234
+
235
+ player.addEventListener('@snice/player-pause', (e) => {
236
+ console.log('Paused:', e.detail.track);
237
+ });
238
+
239
+ player.addEventListener('@snice/player-track-change', (e) => {
240
+ console.log('Track changed:', e.detail.track);
241
+ });
242
+
243
+ player.addEventListener('@snice/player-track-ended', (e) => {
244
+ console.log('Track ended:', e.detail.track);
245
+ });
246
+
247
+ player.addEventListener('@snice/player-time-update', (e) => {
248
+ console.log('Time:', e.detail.currentTime, '/', e.detail.duration);
249
+ });
250
+
251
+ player.addEventListener('@snice/player-error', (e) => {
252
+ console.error('Error:', e.detail.error);
253
+ });
254
+ ```
255
+
256
+ ### Auto-play
257
+
258
+ ```html
259
+ <snice-music-player autoplay></snice-music-player>
260
+ ```
261
+
262
+ **Note:** Autoplay may be blocked by browser policies. User interaction is usually required.
263
+
264
+ ### Dynamic Track Loading
265
+
266
+ ```javascript
267
+ const player = document.querySelector('snice-music-player');
268
+
269
+ // Load tracks from API
270
+ const response = await fetch('/api/tracks');
271
+ const tracks = await response.json();
272
+
273
+ player.tracks = tracks;
274
+ await player.loadTrack(0);
275
+ await player.play();
276
+ ```
277
+
278
+ ### Playlist Click Handler
279
+
280
+ ```javascript
281
+ // Tracks in playlist are clickable by default
282
+ // Listen for track changes
283
+ player.addEventListener('@snice/player-track-change', (e) => {
284
+ console.log('User selected:', e.detail.track.title);
285
+ });
286
+ ```
287
+
288
+ ## Features
289
+
290
+ - Full-featured audio player with HTML5 Audio API
291
+ - Playlist support with clickable tracks
292
+ - Play, pause, stop, next, previous controls
293
+ - Shuffle mode with randomization
294
+ - Repeat modes: off, all, one
295
+ - Volume control with vertical slider
296
+ - Progress bar with seek support
297
+ - Real-time progress updates
298
+ - Track artwork and metadata display
299
+ - Compact mode for smaller layouts
300
+ - Fully customizable with show/hide options
301
+ - Event-driven architecture
302
+ - TypeScript support
303
+
304
+ ## Browser Support
305
+
306
+ - Modern browsers with HTML5 Audio support
307
+ - Requires JavaScript enabled
308
+
309
+ ## Accessibility
310
+
311
+ - Keyboard navigation support
312
+ - ARIA labels on controls
313
+ - Semantic HTML structure
314
+ - Focus indicators