snice 1.1.0 → 1.2.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 +45 -8
- package/package.json +1 -1
- package/src/router.ts +3 -2
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Snice provides a clear separation of concerns through decorators:
|
|
|
23
23
|
- **`@page`** - Sets up routing and navigation between different views
|
|
24
24
|
|
|
25
25
|
### Property & Query Decorators
|
|
26
|
-
- **`@property`** - Declares
|
|
26
|
+
- **`@property`** - Declares properties that can reflect to attributes
|
|
27
27
|
- **`@query`** - Queries a single element from shadow DOM
|
|
28
28
|
- **`@queryAll`** - Queries multiple elements from shadow DOM
|
|
29
29
|
|
|
@@ -219,7 +219,7 @@ class MyClicker extends HTMLElement {
|
|
|
219
219
|
Automatically dispatch custom events with `@dispatch`:
|
|
220
220
|
|
|
221
221
|
```typescript
|
|
222
|
-
import { element, dispatch, on } from 'snice';
|
|
222
|
+
import { element, dispatch, on, query } from 'snice';
|
|
223
223
|
|
|
224
224
|
@element('toggle-switch')
|
|
225
225
|
class ToggleSwitch extends HTMLElement {
|
|
@@ -315,11 +315,22 @@ class AboutPage extends HTMLElement {
|
|
|
315
315
|
}
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
// Page with URL parameter
|
|
319
|
+
@page({ tag: 'user-page', routes: ['/users/:id'] })
|
|
320
|
+
class UserPage extends HTMLElement {
|
|
321
|
+
id = ''; // Automatically set from URL
|
|
322
|
+
|
|
323
|
+
html() {
|
|
324
|
+
return `<h1>User ${this.id}</h1>`;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
318
328
|
// Start the router
|
|
319
329
|
initialize();
|
|
320
330
|
|
|
321
331
|
// Navigate programmatically
|
|
322
332
|
navigate('/about');
|
|
333
|
+
navigate('/users/123'); // Sets id="123" on UserPage
|
|
323
334
|
```
|
|
324
335
|
|
|
325
336
|
## Controllers (Data Fetching)
|
|
@@ -339,7 +350,7 @@ class UserController {
|
|
|
339
350
|
(element as any).setUsers(users);
|
|
340
351
|
}
|
|
341
352
|
|
|
342
|
-
async detach() {
|
|
353
|
+
async detach(element: HTMLElement) {
|
|
343
354
|
// Cleanup
|
|
344
355
|
}
|
|
345
356
|
}
|
|
@@ -358,7 +369,9 @@ class UserList extends HTMLElement {
|
|
|
358
369
|
|
|
359
370
|
setUsers(users: any[]) {
|
|
360
371
|
this.users = users;
|
|
361
|
-
|
|
372
|
+
if (this.shadowRoot) {
|
|
373
|
+
this.shadowRoot.innerHTML = this.html();
|
|
374
|
+
}
|
|
362
375
|
}
|
|
363
376
|
}
|
|
364
377
|
```
|
|
@@ -393,6 +406,11 @@ class UserCard extends HTMLElement {
|
|
|
393
406
|
// --- controllers/user-controller.ts
|
|
394
407
|
@controller('user-controller')
|
|
395
408
|
class UserController {
|
|
409
|
+
element: HTMLElement | null = null;
|
|
410
|
+
|
|
411
|
+
async attach(element: HTMLElement) {}
|
|
412
|
+
async detach(element: HTMLElement) {}
|
|
413
|
+
|
|
396
414
|
@channel('get-data')
|
|
397
415
|
handleGetData(request) {
|
|
398
416
|
console.log(request); // { id: 123 }
|
|
@@ -491,7 +509,6 @@ class WeatherController {
|
|
|
491
509
|
element: HTMLElement | null = null;
|
|
492
510
|
|
|
493
511
|
async attach(element: HTMLElement) {
|
|
494
|
-
this.element = element;
|
|
495
512
|
|
|
496
513
|
// Simulate fetching weather data
|
|
497
514
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
@@ -512,6 +529,10 @@ class WeatherController {
|
|
|
512
529
|
`);
|
|
513
530
|
(element as any).setFooter('Updated just now');
|
|
514
531
|
}
|
|
532
|
+
|
|
533
|
+
async detach(element: HTMLElement) {
|
|
534
|
+
// Cleanup if needed
|
|
535
|
+
}
|
|
515
536
|
}
|
|
516
537
|
```
|
|
517
538
|
|
|
@@ -557,9 +578,16 @@ Use the same card with different controllers:
|
|
|
557
578
|
|
|
558
579
|
```typescript
|
|
559
580
|
interface PropertyOptions {
|
|
560
|
-
type?: typeof String | typeof Number | typeof Boolean; // Type converter
|
|
561
|
-
reflect?: boolean;
|
|
562
|
-
attribute?: string;
|
|
581
|
+
type?: typeof String | typeof Number | typeof Boolean | typeof Array | typeof Object; // Type converter
|
|
582
|
+
reflect?: boolean; // Reflect property to attribute
|
|
583
|
+
attribute?: string | boolean; // Custom attribute name or false to disable
|
|
584
|
+
converter?: PropertyConverter; // Custom converter
|
|
585
|
+
hasChanged?: (value: any, oldValue: any) => boolean; // Custom change detector
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
interface PropertyConverter {
|
|
589
|
+
fromAttribute?(value: string | null, type?: any): any;
|
|
590
|
+
toAttribute?(value: any, type?: any): string | null;
|
|
563
591
|
}
|
|
564
592
|
```
|
|
565
593
|
|
|
@@ -571,6 +599,15 @@ interface DispatchOptions extends EventInit {
|
|
|
571
599
|
}
|
|
572
600
|
```
|
|
573
601
|
|
|
602
|
+
## Documentation
|
|
603
|
+
|
|
604
|
+
- [Elements API](./docs/elements.md) - Complete guide to creating elements with properties, queries, and styling
|
|
605
|
+
- [Controllers API](./docs/controllers.md) - Data fetching, business logic, and controller patterns
|
|
606
|
+
- [Events API](./docs/events.md) - Event handling, dispatching, and custom events
|
|
607
|
+
- [Channels API](./docs/channels.md) - Bidirectional communication between elements and controllers
|
|
608
|
+
- [Routing API](./docs/routing.md) - Single-page application routing with transitions
|
|
609
|
+
- [Migration Guide](./docs/migration-guide.md) - Migrating from React, Vue, Angular, and other frameworks
|
|
610
|
+
|
|
574
611
|
## License
|
|
575
612
|
|
|
576
613
|
MIT
|
package/package.json
CHANGED
package/src/router.ts
CHANGED
|
@@ -108,6 +108,9 @@ export function Router(options: RouterOptions) {
|
|
|
108
108
|
const originalDisconnectedCallback = constructor.prototype.disconnectedCallback;
|
|
109
109
|
|
|
110
110
|
constructor.prototype.connectedCallback = function() {
|
|
111
|
+
// Call original connectedCallback first to allow property initialization
|
|
112
|
+
originalConnectedCallback?.call(this);
|
|
113
|
+
|
|
111
114
|
// Create shadow root if it doesn't exist
|
|
112
115
|
if (!this.shadowRoot) {
|
|
113
116
|
this.attachShadow({ mode: 'open' });
|
|
@@ -139,8 +142,6 @@ export function Router(options: RouterOptions) {
|
|
|
139
142
|
if (shadowContent) {
|
|
140
143
|
this.shadowRoot.innerHTML = shadowContent;
|
|
141
144
|
}
|
|
142
|
-
|
|
143
|
-
originalConnectedCallback?.call(this);
|
|
144
145
|
// Setup @on event handlers - use element for host events, shadow root for delegated events
|
|
145
146
|
setupEventHandlers(this, this);
|
|
146
147
|
};
|