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
package/dist/symbols.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v3.4.1
2
+ * snice v3.6.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.4.1
2
+ * snice v3.6.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.4.1
2
+ * snice v3.6.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.4.1
2
+ * snice v3.6.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,147 @@
1
+ # snice-terminal
2
+
3
+ Shell terminal emulator with command execution, history, ANSI colors, and keyboard navigation.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <snice-terminal prompt="$ " cwd="~"></snice-terminal>
9
+ ```
10
+
11
+ ## Properties
12
+
13
+ - `prompt: string` - Terminal prompt (default: `"$ "`)
14
+ - `cwd: string` - Current working directory (default: `"~"`)
15
+ - `readonly: boolean` - Disable input (default: `false`)
16
+ - `maxLines: number` - Max lines in history (default: `1000`)
17
+ - `showTimestamps: boolean` - Show line timestamps (default: `false`)
18
+
19
+ ## Methods
20
+
21
+ - `write(content: string, type?: TerminalLineType): void` - Write without newline
22
+ - `writeln(content: string, type?: TerminalLineType): void` - Write with newline
23
+ - `writeLines(lines: Array<{ content: string; type?: TerminalLineType }>): void` - Write multiple lines
24
+ - `writeError(content: string): void` - Write error line
25
+ - `clear(): void` - Clear terminal
26
+ - `focus(): void` - Focus input
27
+ - `getHistory(): string[]` - Get command history
28
+ - `clearHistory(): void` - Clear command history
29
+
30
+ ## Events
31
+
32
+ - `@snice/terminal-command: CustomEvent<{ command: string; args: string[] }>` - Command entered
33
+ - `@snice/terminal-clear: CustomEvent<{}>` - Terminal cleared
34
+ - `@snice/terminal-ready: CustomEvent<{}>` - Terminal ready
35
+
36
+ ## Request/Response Pattern
37
+
38
+ Terminal uses `@request('terminal-command')` decorator pattern:
39
+
40
+ ```typescript
41
+ // Terminal component makes request
42
+ @request('terminal-command')
43
+ async *executeCommand(commandLine: string): any {
44
+ const response = await (yield payload);
45
+ return response;
46
+ }
47
+
48
+ // Controller responds
49
+ @respond('terminal-command')
50
+ async handleCommand(payload: TerminalCommandRequest) {
51
+ const { command, args, cwd } = payload;
52
+ // Execute command
53
+ return { output: 'result', exitCode: 0 };
54
+ }
55
+ ```
56
+
57
+ ## Line Types
58
+
59
+ - `input` - User input
60
+ - `output` - Command output
61
+ - `error` - Error message
62
+ - `info` - Info message
63
+ - `success` - Success message
64
+ - `warning` - Warning message
65
+
66
+ ## Keyboard Shortcuts
67
+
68
+ - `Enter` - Execute command
69
+ - `↑/↓` - Navigate history
70
+ - `Ctrl+C` - Cancel input
71
+ - `Ctrl+L` - Clear terminal
72
+ - `Tab` - Command completion (TODO)
73
+
74
+ ## ANSI Color Support
75
+
76
+ Supports ANSI escape codes for colors:
77
+ - `30-37` - Standard colors
78
+ - `90-97` - Bright colors
79
+
80
+ Special output `\x1B[CLEAR]` clears terminal.
81
+
82
+ ## CSS Variables
83
+
84
+ ```css
85
+ --snice-terminal-background
86
+ --snice-terminal-foreground
87
+ --snice-terminal-border
88
+ --snice-terminal-scrollbar
89
+ --snice-terminal-scrollbar-thumb
90
+ --snice-terminal-input-color
91
+ --snice-terminal-output-color
92
+ --snice-terminal-error-color
93
+ --snice-terminal-info-color
94
+ --snice-terminal-success-color
95
+ --snice-terminal-warning-color
96
+ --snice-terminal-prompt-color
97
+ --snice-terminal-selection
98
+ ```
99
+
100
+ ## Types
101
+
102
+ ```typescript
103
+ type TerminalLineType = 'input' | 'output' | 'error' | 'info' | 'success' | 'warning';
104
+
105
+ interface TerminalCommandRequest {
106
+ command: string;
107
+ args: string[];
108
+ cwd?: string;
109
+ history?: string[];
110
+ }
111
+
112
+ interface TerminalCommandResponse {
113
+ output?: string;
114
+ error?: string;
115
+ exitCode?: number;
116
+ }
117
+ ```
118
+
119
+ ## Example
120
+
121
+ ```javascript
122
+ const terminal = document.querySelector('snice-terminal');
123
+
124
+ // Listen for commands (event pattern)
125
+ terminal.addEventListener('@snice/terminal-command', (e) => {
126
+ console.log('Command:', e.detail.command, e.detail.args);
127
+ });
128
+
129
+ // Handle commands (@respond pattern)
130
+ class TerminalController extends HTMLElement {
131
+ @respond('terminal-command')
132
+ async handleCommand(req) {
133
+ if (req.command === 'echo') {
134
+ return { output: req.args.join(' '), exitCode: 0 };
135
+ }
136
+ if (req.command === 'clear') {
137
+ return { output: '\x1B[CLEAR]' };
138
+ }
139
+ return { error: `Command not found: ${req.command}`, exitCode: 127 };
140
+ }
141
+ }
142
+
143
+ // Write to terminal
144
+ terminal.writeln('Welcome to the terminal!', 'info');
145
+ terminal.writeln('\x1b[32mGreen text\x1b[0m', 'output');
146
+ terminal.writeError('Error: Something went wrong');
147
+ ```
@@ -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`
@@ -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`