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 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 reactive properties that can reflect to attributes
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
- this.innerHTML = this.html();
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; // Reflect property to attribute
562
- attribute?: string; // Custom attribute name
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snice",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "A TypeScript library",
6
6
  "main": "src/index.ts",
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
  };