snice 3.5.0 → 3.7.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 (66) hide show
  1. package/bin/snice.js +2 -1
  2. package/bin/templates/CLAUDE.md +24 -2
  3. package/bin/templates/pwa/README.md +173 -0
  4. package/bin/templates/pwa/global.d.ts +10 -0
  5. package/bin/templates/pwa/index.html +17 -0
  6. package/bin/templates/pwa/package.json +25 -0
  7. package/bin/templates/pwa/public/icons/.gitkeep +6 -0
  8. package/bin/templates/pwa/public/manifest.json +24 -0
  9. package/bin/templates/pwa/public/vite.svg +1 -0
  10. package/bin/templates/pwa/src/daemons/notifications.ts +148 -0
  11. package/bin/templates/pwa/src/guards/auth.ts +10 -0
  12. package/bin/templates/pwa/src/main.ts +42 -0
  13. package/bin/templates/pwa/src/middleware/auth.ts +15 -0
  14. package/bin/templates/pwa/src/middleware/error.ts +25 -0
  15. package/bin/templates/pwa/src/middleware/retry.ts +27 -0
  16. package/bin/templates/pwa/src/pages/dashboard.ts +142 -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 +163 -0
  20. package/bin/templates/pwa/src/router.ts +16 -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/src/utils/fetch.ts +39 -0
  28. package/bin/templates/pwa/tsconfig.json +23 -0
  29. package/bin/templates/pwa/vite.config.ts +94 -0
  30. package/dist/components/audio-recorder/snice-audio-recorder.d.ts +14 -4
  31. package/dist/components/audio-recorder/snice-audio-recorder.js +248 -71
  32. package/dist/components/audio-recorder/snice-audio-recorder.js.map +1 -1
  33. package/dist/components/audio-recorder/snice-audio-recorder.types.d.ts +2 -0
  34. package/dist/components/music-player/snice-music-player.d.ts +72 -0
  35. package/dist/components/music-player/snice-music-player.js +730 -0
  36. package/dist/components/music-player/snice-music-player.js.map +1 -0
  37. package/dist/components/music-player/snice-music-player.types.d.ts +43 -0
  38. package/dist/components/timer/snice-timer.d.ts +27 -0
  39. package/dist/components/timer/snice-timer.js +197 -0
  40. package/dist/components/timer/snice-timer.js.map +1 -0
  41. package/dist/components/timer/snice-timer.types.d.ts +10 -0
  42. package/dist/fetcher.d.ts +65 -0
  43. package/dist/index.cjs +92 -3
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.ts +2 -0
  46. package/dist/index.esm.js +92 -4
  47. package/dist/index.esm.js.map +1 -1
  48. package/dist/index.iife.js +92 -3
  49. package/dist/index.iife.js.map +1 -1
  50. package/dist/symbols.cjs +1 -1
  51. package/dist/symbols.esm.js +1 -1
  52. package/dist/transitions.cjs +1 -1
  53. package/dist/transitions.esm.js +1 -1
  54. package/dist/types/context.d.ts +7 -1
  55. package/dist/types/router-options.d.ts +6 -0
  56. package/docs/ai/api.md +33 -1
  57. package/docs/ai/components/music-player.md +134 -0
  58. package/docs/ai/components/terminal.md +147 -0
  59. package/docs/ai/components/timer.md +43 -0
  60. package/docs/ai/patterns.md +47 -0
  61. package/docs/components/music-player.md +314 -0
  62. package/docs/components/terminal.md +451 -0
  63. package/docs/components/timer.md +143 -0
  64. package/docs/fetcher.md +447 -0
  65. package/docs/routing.md +2 -0
  66. package/package.json +2 -1
@@ -0,0 +1,451 @@
1
+ # snice-terminal
2
+
3
+ A shell terminal emulator component with command execution, history navigation, ANSI color support, and keyboard shortcuts.
4
+
5
+ ## Features
6
+
7
+ - **Command execution** - Execute commands with @request/@respond pattern
8
+ - **Command history** - Navigate with arrow keys (↑/↓)
9
+ - **ANSI colors** - Support for ANSI escape sequences
10
+ - **Keyboard shortcuts** - Ctrl+C, Ctrl+L, Tab (planned)
11
+ - **Readonly mode** - Display-only terminal output
12
+ - **Line management** - Auto-scroll and line limit
13
+ - **Timestamps** - Optional timestamp display
14
+ - **Customizable styling** - CSS custom properties for theming
15
+
16
+ ## Basic Usage
17
+
18
+ ```html
19
+ <snice-terminal id="terminal" prompt="$ " cwd="~"></snice-terminal>
20
+
21
+ <script type="module">
22
+ import 'snice';
23
+
24
+ const terminal = document.getElementById('terminal');
25
+
26
+ // Write to terminal
27
+ terminal.writeln('Welcome to the terminal!', 'info');
28
+ terminal.writeln('Type "help" for commands', 'output');
29
+ </script>
30
+ ```
31
+
32
+ ## Properties
33
+
34
+ | Property | Attribute | Type | Default | Description |
35
+ | ----------------- | ------------------ | --------- | ---------- | ------------------------------------- |
36
+ | `prompt` | `prompt` | `string` | `"$ "` | Terminal prompt string |
37
+ | `cwd` | `cwd` | `string` | `"~"` | Current working directory |
38
+ | `readonly` | `readonly` | `boolean` | `false` | Disable input (display only) |
39
+ | `maxLines` | `max-lines` | `number` | `1000` | Maximum lines to keep in history |
40
+ | `showTimestamps` | `show-timestamps` | `boolean` | `false` | Show timestamps on each line |
41
+
42
+ ## Methods
43
+
44
+ ### `write(content: string, type?: TerminalLineType): void`
45
+
46
+ Write content to terminal without adding a newline.
47
+
48
+ ```javascript
49
+ terminal.write('Loading', 'output');
50
+ terminal.write('...', 'output');
51
+ ```
52
+
53
+ ### `writeln(content: string, type?: TerminalLineType): void`
54
+
55
+ Write a line to the terminal with a newline.
56
+
57
+ ```javascript
58
+ terminal.writeln('Command completed successfully', 'success');
59
+ terminal.writeln('Warning: Low disk space', 'warning');
60
+ ```
61
+
62
+ ### `writeLines(lines: Array<{ content: string; type?: TerminalLineType }>): void`
63
+
64
+ Write multiple lines at once.
65
+
66
+ ```javascript
67
+ terminal.writeLines([
68
+ { content: 'File listing:', type: 'info' },
69
+ { content: 'file1.txt', type: 'output' },
70
+ { content: 'file2.txt', type: 'output' },
71
+ { content: 'file3.txt', type: 'output' },
72
+ ]);
73
+ ```
74
+
75
+ ### `writeError(content: string): void`
76
+
77
+ Write an error message to the terminal.
78
+
79
+ ```javascript
80
+ terminal.writeError('Error: File not found');
81
+ ```
82
+
83
+ ### `clear(): void`
84
+
85
+ Clear all terminal output.
86
+
87
+ ```javascript
88
+ terminal.clear();
89
+ ```
90
+
91
+ ### `focus(): void`
92
+
93
+ Focus the terminal input.
94
+
95
+ ```javascript
96
+ terminal.focus();
97
+ ```
98
+
99
+ ### `getHistory(): string[]`
100
+
101
+ Get the command history.
102
+
103
+ ```javascript
104
+ const history = terminal.getHistory();
105
+ console.log('Command history:', history);
106
+ ```
107
+
108
+ ### `clearHistory(): void`
109
+
110
+ Clear the command history.
111
+
112
+ ```javascript
113
+ terminal.clearHistory();
114
+ ```
115
+
116
+ ## Events
117
+
118
+ ### `@snice/terminal-command`
119
+
120
+ Emitted when a command is entered.
121
+
122
+ ```javascript
123
+ terminal.addEventListener('@snice/terminal-command', (e) => {
124
+ console.log('Command:', e.detail.command);
125
+ console.log('Args:', e.detail.args);
126
+ });
127
+ ```
128
+
129
+ **Detail:**
130
+ - `command: string` - The command name
131
+ - `args: string[]` - Command arguments
132
+
133
+ ### `@snice/terminal-clear`
134
+
135
+ Emitted when the terminal is cleared.
136
+
137
+ ```javascript
138
+ terminal.addEventListener('@snice/terminal-clear', () => {
139
+ console.log('Terminal was cleared');
140
+ });
141
+ ```
142
+
143
+ ### `@snice/terminal-ready`
144
+
145
+ Emitted when the terminal is ready.
146
+
147
+ ```javascript
148
+ terminal.addEventListener('@snice/terminal-ready', () => {
149
+ console.log('Terminal is ready');
150
+ });
151
+ ```
152
+
153
+ ## Command Execution Pattern
154
+
155
+ The terminal uses Snice's `@request`/`@respond` pattern for command execution:
156
+
157
+ ```javascript
158
+ import { element, respond } from 'snice';
159
+
160
+ @element('terminal-controller')
161
+ class TerminalController extends HTMLElement {
162
+ @respond('terminal-command')
163
+ async handleCommand(payload) {
164
+ const { command, args, cwd, history } = payload;
165
+
166
+ // Handle different commands
167
+ switch (command) {
168
+ case 'echo':
169
+ return { output: args.join(' '), exitCode: 0 };
170
+
171
+ case 'pwd':
172
+ return { output: cwd, exitCode: 0 };
173
+
174
+ case 'clear':
175
+ // Special marker to trigger clear
176
+ return { output: '\x1B[CLEAR]' };
177
+
178
+ case 'history':
179
+ return { output: history.join('\n'), exitCode: 0 };
180
+
181
+ default:
182
+ return {
183
+ error: `Command not found: ${command}`,
184
+ exitCode: 127,
185
+ };
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ ## Line Types
192
+
193
+ The terminal supports different line types for styling:
194
+
195
+ - `input` - User input echoed back
196
+ - `output` - Standard command output
197
+ - `error` - Error messages (red)
198
+ - `info` - Information messages (blue)
199
+ - `success` - Success messages (green)
200
+ - `warning` - Warning messages (yellow)
201
+
202
+ ```javascript
203
+ terminal.writeln('This is output', 'output');
204
+ terminal.writeln('This is an error', 'error');
205
+ terminal.writeln('This is info', 'info');
206
+ terminal.writeln('This is success', 'success');
207
+ terminal.writeln('This is a warning', 'warning');
208
+ ```
209
+
210
+ ## Keyboard Shortcuts
211
+
212
+ | Key | Action |
213
+ | ----------- | -------------------------- |
214
+ | `Enter` | Execute command |
215
+ | `↑` | Previous command (history) |
216
+ | `↓` | Next command (history) |
217
+ | `Ctrl+C` | Cancel current input |
218
+ | `Ctrl+L` | Clear terminal |
219
+ | `Tab` | Auto-complete (TODO) |
220
+
221
+ ## ANSI Color Support
222
+
223
+ The terminal supports ANSI escape sequences for colored output:
224
+
225
+ ```javascript
226
+ // Standard colors (30-37)
227
+ terminal.writeln('\x1b[31mRed text\x1b[0m', 'output');
228
+ terminal.writeln('\x1b[32mGreen text\x1b[0m', 'output');
229
+ terminal.writeln('\x1b[33mYellow text\x1b[0m', 'output');
230
+ terminal.writeln('\x1b[34mBlue text\x1b[0m', 'output');
231
+ terminal.writeln('\x1b[35mMagenta text\x1b[0m', 'output');
232
+ terminal.writeln('\x1b[36mCyan text\x1b[0m', 'output');
233
+ terminal.writeln('\x1b[37mWhite text\x1b[0m', 'output');
234
+
235
+ // Bright colors (90-97)
236
+ terminal.writeln('\x1b[91mBright Red\x1b[0m', 'output');
237
+ terminal.writeln('\x1b[92mBright Green\x1b[0m', 'output');
238
+ terminal.writeln('\x1b[93mBright Yellow\x1b[0m', 'output');
239
+ terminal.writeln('\x1b[94mBright Blue\x1b[0m', 'output');
240
+
241
+ // Reset
242
+ terminal.writeln('\x1b[0mReset to default\x1b[0m', 'output');
243
+ ```
244
+
245
+ **ANSI Color Map:**
246
+ - `30` / `90` - Black / Bright Black
247
+ - `31` / `91` - Red / Bright Red
248
+ - `32` / `92` - Green / Bright Green
249
+ - `33` / `93` - Yellow / Bright Yellow
250
+ - `34` / `94` - Blue / Bright Blue
251
+ - `35` / `95` - Magenta / Bright Magenta
252
+ - `36` / `96` - Cyan / Bright Cyan
253
+ - `37` / `97` - White / Bright White
254
+ - `0` - Reset
255
+
256
+ ## Styling
257
+
258
+ The component can be styled using CSS custom properties:
259
+
260
+ ```css
261
+ snice-terminal {
262
+ /* Container */
263
+ --snice-terminal-background: #1e1e1e;
264
+ --snice-terminal-foreground: #d4d4d4;
265
+ --snice-terminal-border: #3c3c3c;
266
+
267
+ /* Scrollbar */
268
+ --snice-terminal-scrollbar: #424242;
269
+ --snice-terminal-scrollbar-thumb: #686868;
270
+
271
+ /* Line types */
272
+ --snice-terminal-input-color: #d4d4d4;
273
+ --snice-terminal-output-color: #cccccc;
274
+ --snice-terminal-error-color: #ff5555;
275
+ --snice-terminal-info-color: #569cd6;
276
+ --snice-terminal-success-color: #50fa7b;
277
+ --snice-terminal-warning-color: #f1fa8c;
278
+
279
+ /* Prompt */
280
+ --snice-terminal-prompt-color: #569cd6;
281
+
282
+ /* Selection */
283
+ --snice-terminal-selection: rgba(255, 255, 255, 0.2);
284
+ }
285
+ ```
286
+
287
+ ## Examples
288
+
289
+ ### Basic Terminal
290
+
291
+ ```html
292
+ <snice-terminal id="terminal"></snice-terminal>
293
+
294
+ <script type="module">
295
+ import 'snice';
296
+
297
+ const terminal = document.getElementById('terminal');
298
+
299
+ terminal.writeln('Welcome to the terminal!', 'info');
300
+ terminal.writeln('Type commands to get started', 'output');
301
+ </script>
302
+ ```
303
+
304
+ ### With Command Handler
305
+
306
+ ```html
307
+ <terminal-controller></terminal-controller>
308
+ <snice-terminal id="terminal" prompt="myapp $ "></snice-terminal>
309
+
310
+ <script type="module">
311
+ import { element, respond } from 'snice';
312
+
313
+ @element('terminal-controller')
314
+ class TerminalController extends HTMLElement {
315
+ @respond('terminal-command')
316
+ async handleCommand(payload) {
317
+ const { command, args } = payload;
318
+
319
+ switch (command) {
320
+ case 'hello':
321
+ return { output: `Hello, ${args[0] || 'World'}!`, exitCode: 0 };
322
+
323
+ case 'date':
324
+ return { output: new Date().toString(), exitCode: 0 };
325
+
326
+ case 'help':
327
+ return {
328
+ output: 'Available commands:\n hello [name]\n date\n help\n clear',
329
+ exitCode: 0,
330
+ };
331
+
332
+ case 'clear':
333
+ return { output: '\x1B[CLEAR]' };
334
+
335
+ default:
336
+ return {
337
+ error: `Unknown command: ${command}`,
338
+ exitCode: 1,
339
+ };
340
+ }
341
+ }
342
+ }
343
+
344
+ const terminal = document.getElementById('terminal');
345
+ terminal.writeln('Type "help" for available commands', 'info');
346
+ </script>
347
+ ```
348
+
349
+ ### Readonly Terminal
350
+
351
+ ```html
352
+ <snice-terminal id="log-viewer" readonly show-timestamps></snice-terminal>
353
+
354
+ <script type="module">
355
+ import 'snice';
356
+
357
+ const logViewer = document.getElementById('log-viewer');
358
+
359
+ // Simulate log streaming
360
+ setInterval(() => {
361
+ const logTypes = ['info', 'warning', 'error', 'success'];
362
+ const type = logTypes[Math.floor(Math.random() * logTypes.length)];
363
+ const message = `Log entry at ${new Date().toISOString()}`;
364
+ logViewer.writeln(message, type);
365
+ }, 2000);
366
+ </script>
367
+ ```
368
+
369
+ ### With ANSI Colors
370
+
371
+ ```html
372
+ <snice-terminal id="terminal"></snice-terminal>
373
+
374
+ <script type="module">
375
+ import 'snice';
376
+
377
+ const terminal = document.getElementById('terminal');
378
+
379
+ terminal.writeln('\x1b[1m\x1b[32mSuccess!\x1b[0m Operation completed', 'output');
380
+ terminal.writeln('\x1b[31mError:\x1b[0m Something went wrong', 'output');
381
+ terminal.writeln('\x1b[33mWarning:\x1b[0m Disk space low', 'output');
382
+ terminal.writeln('\x1b[36mInfo:\x1b[0m Processing...', 'output');
383
+ </script>
384
+ ```
385
+
386
+ ### Async Command Execution
387
+
388
+ ```html
389
+ <terminal-controller></terminal-controller>
390
+ <snice-terminal id="terminal"></snice-terminal>
391
+
392
+ <script type="module">
393
+ import { element, respond } from 'snice';
394
+
395
+ @element('terminal-controller')
396
+ class TerminalController extends HTMLElement {
397
+ @respond('terminal-command')
398
+ async handleCommand(payload) {
399
+ const { command, args } = payload;
400
+
401
+ if (command === 'fetch') {
402
+ const url = args[0];
403
+ if (!url) {
404
+ return { error: 'Usage: fetch <url>', exitCode: 1 };
405
+ }
406
+
407
+ try {
408
+ const response = await fetch(url);
409
+ const data = await response.json();
410
+ return { output: JSON.stringify(data, null, 2), exitCode: 0 };
411
+ } catch (error) {
412
+ return { error: `Fetch failed: ${error.message}`, exitCode: 1 };
413
+ }
414
+ }
415
+
416
+ if (command === 'sleep') {
417
+ const seconds = parseInt(args[0]) || 1;
418
+ await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
419
+ return { output: `Slept for ${seconds} seconds`, exitCode: 0 };
420
+ }
421
+
422
+ return { error: `Unknown command: ${command}`, exitCode: 127 };
423
+ }
424
+ }
425
+ </script>
426
+ ```
427
+
428
+ ## Browser Support
429
+
430
+ Works in all modern browsers that support:
431
+ - Custom Elements v1
432
+ - Shadow DOM
433
+ - ES2020+
434
+
435
+ ## TypeScript
436
+
437
+ Full TypeScript support with exported types:
438
+
439
+ ```typescript
440
+ import type {
441
+ SniceTerminalElement,
442
+ TerminalLine,
443
+ TerminalLineType,
444
+ TerminalCommandRequest,
445
+ TerminalCommandResponse,
446
+ } from 'snice/terminal';
447
+ ```
448
+
449
+ ## Security Note
450
+
451
+ The terminal uses `unsafeHTML` for rendering ANSI-colored output. Only use trusted content or sanitize user input before displaying.
@@ -0,0 +1,143 @@
1
+ # Timer Component
2
+
3
+ The `<snice-timer>` component provides a stopwatch and countdown timer.
4
+
5
+ ## Basic Usage
6
+
7
+ ```html
8
+ <!-- Stopwatch -->
9
+ <snice-timer mode="stopwatch"></snice-timer>
10
+
11
+ <!-- Countdown Timer -->
12
+ <snice-timer mode="timer" initial-time="60"></snice-timer>
13
+ ```
14
+
15
+ ## Properties
16
+
17
+ | Property | Type | Default | Description |
18
+ |----------|------|---------|-------------|
19
+ | `mode` | `'stopwatch' \| 'timer'` | `'stopwatch'` | Timer mode |
20
+ | `initial-time` | `number` | `0` | Starting time in seconds (for timer mode) |
21
+ | `running` | `boolean` | `false` | Timer running state (read-only) |
22
+
23
+ ## Methods
24
+
25
+ | Method | Returns | Description |
26
+ |--------|---------|-------------|
27
+ | `start()` | `void` | Start the timer |
28
+ | `stop()` | `void` | Stop/pause the timer |
29
+ | `reset()` | `void` | Reset to initial state |
30
+ | `getTime()` | `number` | Get current time in seconds |
31
+
32
+ ## Events
33
+
34
+ | Event | Detail | Description |
35
+ |-------|--------|-------------|
36
+ | `@snice/timer-start` | `{ timer, time }` | Timer started |
37
+ | `@snice/timer-stop` | `{ timer, time }` | Timer stopped |
38
+ | `@snice/timer-reset` | `{ timer, time }` | Timer reset |
39
+ | `@snice/timer-complete` | `{ timer }` | Countdown completed (timer mode only) |
40
+
41
+ ## Examples
42
+
43
+ ### Stopwatch
44
+
45
+ ```html
46
+ <snice-timer id="stopwatch" mode="stopwatch"></snice-timer>
47
+
48
+ <script>
49
+ const stopwatch = document.getElementById('stopwatch');
50
+ stopwatch.start();
51
+
52
+ // Later...
53
+ stopwatch.stop();
54
+ console.log('Elapsed:', stopwatch.getTime(), 'seconds');
55
+ </script>
56
+ ```
57
+
58
+ ### Countdown Timer
59
+
60
+ ```html
61
+ <snice-timer id="timer" mode="timer" initial-time="300"></snice-timer>
62
+
63
+ <script>
64
+ const timer = document.getElementById('timer');
65
+
66
+ timer.addEventListener('@snice/timer-complete', () => {
67
+ console.log('Time is up!');
68
+ });
69
+
70
+ timer.start();
71
+ </script>
72
+ ```
73
+
74
+ ### Programmatic Control
75
+
76
+ ```html
77
+ <snice-timer id="my-timer"></snice-timer>
78
+
79
+ <button onclick="document.getElementById('my-timer').start()">Start</button>
80
+ <button onclick="document.getElementById('my-timer').stop()">Stop</button>
81
+ <button onclick="document.getElementById('my-timer').reset()">Reset</button>
82
+
83
+ <script>
84
+ const timer = document.getElementById('my-timer');
85
+
86
+ timer.addEventListener('@snice/timer-start', (e) => {
87
+ console.log('Timer started at', e.detail.time);
88
+ });
89
+
90
+ timer.addEventListener('@snice/timer-stop', (e) => {
91
+ console.log('Timer stopped at', e.detail.time);
92
+ });
93
+ </script>
94
+ ```
95
+
96
+ ### Workout Timer
97
+
98
+ ```html
99
+ <snice-timer id="workout" mode="timer" initial-time="45"></snice-timer>
100
+
101
+ <script>
102
+ const workout = document.getElementById('workout');
103
+
104
+ workout.addEventListener('@snice/timer-complete', () => {
105
+ alert('Rest time!');
106
+ // Start rest period
107
+ workout.initialTime = 15;
108
+ workout.reset();
109
+ workout.start();
110
+ });
111
+
112
+ workout.start();
113
+ </script>
114
+ ```
115
+
116
+ ## Styling
117
+
118
+ The timer uses CSS custom properties from the theme system:
119
+
120
+ ```css
121
+ snice-timer {
122
+ --snice-color-background-element: rgb(252 251 249);
123
+ --snice-color-border: rgb(226 226 226);
124
+ --snice-color-text: rgb(23 23 23);
125
+ --snice-color-success: rgb(22 163 74);
126
+ --snice-color-warning: rgb(202 138 4);
127
+ --snice-color-neutral: rgb(82 82 82);
128
+ }
129
+ ```
130
+
131
+ ## Accessibility
132
+
133
+ - Large, readable time display
134
+ - Clear button labels and icons
135
+ - Keyboard accessible controls
136
+ - High contrast buttons
137
+
138
+ ## Best Practices
139
+
140
+ 1. **Choose the right mode**: Use stopwatch for tracking elapsed time, timer for countdowns
141
+ 2. **Handle timer-complete**: Listen for completion events in timer mode
142
+ 3. **Provide context**: Add labels or descriptions near the timer
143
+ 4. **Reset appropriately**: Call `reset()` to return to initial state