@dooboostore/simple-web-component 1.0.38 → 1.0.40

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 (91) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +88 -871
  3. package/dist/cjs/SwcAppEngine.js.map +2 -2
  4. package/dist/cjs/decorators/applyAttribute.js +194 -111
  5. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  6. package/dist/cjs/decorators/applyNode.js +82 -80
  7. package/dist/cjs/decorators/applyNode.js.map +2 -2
  8. package/dist/cjs/decorators/applyProperty.js +213 -0
  9. package/dist/cjs/decorators/applyProperty.js.map +7 -0
  10. package/dist/cjs/decorators/applySlot.js +93 -82
  11. package/dist/cjs/decorators/applySlot.js.map +3 -3
  12. package/dist/cjs/decorators/changedAttributeThis.js.map +1 -1
  13. package/dist/cjs/decorators/elementDefine.js +14 -34
  14. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  15. package/dist/cjs/decorators/index.js +2 -2
  16. package/dist/cjs/decorators/index.js.map +2 -2
  17. package/dist/cjs/decorators/lifecycles.js +4 -4
  18. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  19. package/dist/cjs/decorators/state.js +0 -1
  20. package/dist/cjs/decorators/state.js.map +2 -2
  21. package/dist/cjs/elements/SwcApp.js.map +2 -2
  22. package/dist/cjs/types/index.js.map +1 -1
  23. package/dist/esm/SwcAppEngine.js.map +2 -2
  24. package/dist/esm/decorators/applyAttribute.js +196 -113
  25. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  26. package/dist/esm/decorators/applyNode.js +82 -80
  27. package/dist/esm/decorators/applyNode.js.map +2 -2
  28. package/dist/esm/decorators/applyProperty.js +194 -0
  29. package/dist/esm/decorators/applyProperty.js.map +7 -0
  30. package/dist/esm/decorators/applySlot.js +93 -82
  31. package/dist/esm/decorators/applySlot.js.map +3 -3
  32. package/dist/esm/decorators/changedAttributeThis.js.map +1 -1
  33. package/dist/esm/decorators/elementDefine.js +14 -34
  34. package/dist/esm/decorators/elementDefine.js.map +2 -2
  35. package/dist/esm/decorators/index.js +2 -2
  36. package/dist/esm/decorators/index.js.map +1 -1
  37. package/dist/esm/decorators/lifecycles.js +4 -4
  38. package/dist/esm/decorators/lifecycles.js.map +2 -2
  39. package/dist/esm/decorators/state.js +0 -1
  40. package/dist/esm/decorators/state.js.map +2 -2
  41. package/dist/esm/elements/SwcApp.js.map +2 -2
  42. package/dist/esm/types/index.js.map +1 -1
  43. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +525 -513
  44. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  45. package/dist/types/SwcAppEngine.d.ts.map +1 -1
  46. package/dist/types/decorators/applyAttribute.d.ts +56 -15
  47. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  48. package/dist/types/decorators/applyNode.d.ts +28 -24
  49. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  50. package/dist/types/decorators/applyProperty.d.ts +61 -0
  51. package/dist/types/decorators/applyProperty.d.ts.map +1 -0
  52. package/dist/types/decorators/applySlot.d.ts +17 -15
  53. package/dist/types/decorators/applySlot.d.ts.map +1 -1
  54. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  55. package/dist/types/decorators/index.d.ts +2 -2
  56. package/dist/types/decorators/index.d.ts.map +1 -1
  57. package/dist/types/decorators/lifecycles.d.ts +4 -4
  58. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  59. package/dist/types/decorators/state.d.ts.map +1 -1
  60. package/dist/types/elements/SwcApp.d.ts.map +1 -1
  61. package/dist/types/types/index.d.ts +1 -6
  62. package/dist/types/types/index.d.ts.map +1 -1
  63. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +525 -513
  64. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  65. package/package.json +1 -1
  66. package/src/SwcAppEngine.ts +1 -0
  67. package/src/decorators/applyAttribute.ts +311 -126
  68. package/src/decorators/applyNode.ts +108 -105
  69. package/src/decorators/applyProperty.ts +302 -0
  70. package/src/decorators/applySlot.ts +112 -94
  71. package/src/decorators/changedAttributeThis.ts +1 -1
  72. package/src/decorators/elementDefine.ts +44 -33
  73. package/src/decorators/index.ts +2 -3
  74. package/src/decorators/lifecycles.ts +6 -6
  75. package/src/decorators/state.ts +0 -1
  76. package/src/elements/SwcApp.ts +0 -1
  77. package/src/types/index.ts +7 -7
  78. package/dist/cjs/decorators/attribute.js +0 -187
  79. package/dist/cjs/decorators/attribute.js.map +0 -7
  80. package/dist/cjs/decorators/setProperty.js +0 -109
  81. package/dist/cjs/decorators/setProperty.js.map +0 -7
  82. package/dist/esm/decorators/attribute.js +0 -168
  83. package/dist/esm/decorators/attribute.js.map +0 -7
  84. package/dist/esm/decorators/setProperty.js +0 -90
  85. package/dist/esm/decorators/setProperty.js.map +0 -7
  86. package/dist/types/decorators/attribute.d.ts +0 -31
  87. package/dist/types/decorators/attribute.d.ts.map +0 -1
  88. package/dist/types/decorators/setProperty.d.ts +0 -17
  89. package/dist/types/decorators/setProperty.d.ts.map +0 -1
  90. package/src/decorators/attribute.ts +0 -223
  91. package/src/decorators/setProperty.ts +0 -112
package/README.md CHANGED
@@ -30,7 +30,7 @@ Inject services into Web Components using the `@onInitialize` decorator.
30
30
  class Dashboard extends HTMLElement {
31
31
  @onInitialize
32
32
  onconstructor(
33
- @Inject({ symbol: UserService.SYMBOL }) userService: UserService
33
+ @inject(UserService.SYMBOL) userService: UserService
34
34
  ) {
35
35
  this.userService = userService;
36
36
  }
@@ -39,84 +39,74 @@ class Dashboard extends HTMLElement {
39
39
 
40
40
  ### 3. **Declarative DOM Updates**
41
41
 
42
- #### @onConnectedInnerHtml
42
+ #### @onConnectedShadow
43
43
  Render HTML automatically when component connects to DOM.
44
44
 
45
45
  ```typescript
46
- @onConnectedInnerHtml({ useShadow: true })
46
+ @onConnectedShadow
47
47
  render() {
48
48
  return `<div>Hello, <span>${this.name}</span>!</div>`;
49
49
  }
50
50
  ```
51
51
 
52
- #### @applyNodeThisInnerHtml
52
+ #### @innerHtmlLightNodeThis
53
53
  Apply HTML to specific host element.
54
54
 
55
55
  ```typescript
56
- @applyNodeThisInnerHtml({ root: 'light' })
56
+ @innerHtmlLightNodeThis
57
57
  updateContent() {
58
58
  return `<p>Updated content</p>`;
59
59
  }
60
60
  ```
61
61
 
62
- #### @applyNodeThisReplaceChildren
62
+ #### @replaceChildrenLightNodeThis
63
63
  Replace child nodes with new content.
64
64
 
65
65
  ```typescript
66
- @applyNodeThisReplaceChildren({ root: 'light' })
66
+ @replaceChildrenLightNodeThis
67
67
  replaceChildren(node: Node) {
68
68
  return node;
69
69
  }
70
+ ```
70
71
  ### 3.5 **Slot Management with @applySlot**
71
72
 
72
73
  Manage dynamic content insertion into named slots using the `@applySlot` decorator. Slots are placeholders in templates that can be updated dynamically.
73
74
 
74
75
  ```typescript
76
+ import {clearSlot} from "./applySlot";
77
+
75
78
  @elementDefine('content-manager')
76
79
  class ContentManager extends HTMLElement {
77
- // Property: Get NodeSlot instance for manual slot manipulation
78
- @applySlot('main-content')
79
- mainSlot?: NodeSlot;
80
80
 
81
- @applySlot('sidebar')
82
- sidebarSlot?: NodeSlot;
83
81
 
84
82
  // Method: Replace children in slot with HTML
85
83
  @addEventListener('.update-btn', 'click')
86
- @applySlotReplaceChildren('main-content')
84
+ @replaceChildrenSlot('main-content')
87
85
  updateContent() {
88
86
  return '<div>Updated content here</div>';
89
87
  }
90
88
 
91
89
  // Method: Append HTML to slot
92
- @applySlotAppendHtml('main-content')
90
+ @appendHtmlSlot('main-content')
93
91
  addMoreContent() {
94
92
  return '<p>Additional content</p>';
95
93
  }
96
94
 
97
95
  // Method: Append text to slot
98
- @applySlotAppendText('sidebar')
96
+ @appendTextSlot('sidebar')
99
97
  addSidebarText() {
100
98
  return 'Sidebar text: ' + new Date().toISOString();
101
99
  }
102
100
 
103
101
  // Method: Clear slot content
104
102
  @addEventListener('.clear-btn', 'click')
105
- @applySlotClear('main-content')
103
+ @clearSlot('main-content')
106
104
  clearContent() {
107
105
  return true;
108
106
  }
109
107
 
110
- // Lifecycle: Manual slot manipulation
111
- @onConnectedAfter
112
- setupSlots() {
113
- // Access slot via property for manual manipulation
114
- if (this.mainSlot) {
115
- this.mainSlot.appendText('main-content', 'Initial text');
116
- }
117
- }
118
108
 
119
- @onConnectedInnerHtml
109
+ @onConnectedLight
120
110
  render() {
121
111
  return `
122
112
  <div>
@@ -140,39 +130,33 @@ class ContentManager extends HTMLElement {
140
130
  - `<!--[[ slot-id ]]-->` - Named slot placeholder (HTML comment syntax)
141
131
 
142
132
  **@applySlot Decorator Variants:**
143
- - `@applySlot(id, options)` - Generic slot operation with position option
144
- - `@applySlotReplaceChildren(id)` - Replace all children with HTML
145
- - `@applySlotReplaceChildrenText(id)` - Replace all children with text
146
- - `@applySlotAppendHtml(id)` - Append HTML to slot
147
- - `@applySlotAppendText(id)` - Append text to slot
148
- - `@applySlotPrependHtml(id)` - Prepend HTML to slot
149
- - `@applySlotPrependText(id)` - Prepend text to slot
150
- - `@applySlotClear(id)` - Clear slot content
133
+ - clearSlot
134
+ - prependHtmlSlot
135
+ - prependSlot
136
+ - prependTextSlot
137
+ - appendHtmlSlot
138
+ - appendTextSlot
139
+ - appendSlot
140
+ - replaceChildrenHtmlSlot
141
+ - replaceChildrenSlot
142
+ - replaceChildrenTextSlot
143
+
151
144
 
152
145
  **Position Options:**
153
146
  ```typescript
154
147
  export type ApplySlotPosition =
148
+ | 'prepend'
155
149
  | 'prependHtml' // Add HTML at beginning
156
150
  | 'prependText' // Add text at beginning
151
+ | 'append'
157
152
  | 'appendHtml' // Add HTML at end
158
153
  | 'appendText' // Add text at end
154
+ | 'replaceChildren'
159
155
  | 'replaceChildrenHtml' // Replace all with HTML
160
156
  | 'replaceChildrenText' // Replace all with text
161
157
  | 'clear'; // Clear all content
162
158
  ```
163
159
 
164
- **Manual Slot Manipulation:**
165
- ```typescript
166
- // Via @applySlot property
167
- @applySlot('content')
168
- contentSlot?: NodeSlot;
169
-
170
- // In lifecycle or methods
171
- this.contentSlot?.appendHtml('content', '<p>New content</p>');
172
- this.contentSlot?.appendText('content', 'Text content');
173
- this.contentSlot?.replaceChildrenHtml('content', '<div>Replaced</div>');
174
- this.contentSlot?.clear('content');
175
- ```
176
160
 
177
161
  ### 3.6 **State Management with @state**
178
162
 
@@ -207,14 +191,13 @@ class CounterApp extends HTMLElement {
207
191
  <!--[text Count: @count@ ]-->
208
192
 
209
193
  <!-- Attribute binding with a: prefix -->
210
- <div a:title="Count is @count@"></div>
194
+ <div a:title="'Count is'+@count@"></div>
211
195
 
212
196
  <!-- Event binding with e: prefix -->
213
- <button e:click="increment">Increment (@count@)</button>
197
+ <button e:click="@increment@()">Increment (@count@)</button>
214
198
 
215
199
  <!-- Conditional rendering -->
216
200
  <div a:style="@isActive@ ? 'color: green' : 'color: red'">
217
- Status: @isActive@
218
201
  </div>
219
202
  </div>
220
203
  `;
@@ -233,7 +216,7 @@ class CounterApp extends HTMLElement {
233
216
  - `<!--[html @state@ ]-->` - Render state value as HTML
234
217
  - `<!--[text @state@ ]-->` - Render state value as text
235
218
  - `a:attributeName="@state@"` - Bind state to HTML attributes
236
- - `e:eventName="methodName"` - Bind events to methods
219
+ - `e:eventName="@methodName@()"` - Bind events to methods
237
220
 
238
221
  **How @state Works:**
239
222
  1. Declare property with `@state('stateName')`
@@ -263,7 +246,7 @@ class UserProfile extends HTMLElement {
263
246
  this.isEditing = !this.isEditing;
264
247
  }
265
248
 
266
- @onConnectedInnerHtml
249
+ @onConnectedShadow
267
250
  render() {
268
251
  return `
269
252
  <div>
@@ -276,9 +259,7 @@ class UserProfile extends HTMLElement {
276
259
  <!--[html @isEditing@ ? '<input type="text" />' : '<span>View Mode</span>' ]-->
277
260
  </div>
278
261
 
279
- <button e:click="toggleEdit">
280
- @isEditing@ ? 'Save' : 'Edit'
281
- </button>
262
+ <button e:click="toggleEdit"> toggleEdit </button>
282
263
  </div>
283
264
  `;
284
265
  }
@@ -307,6 +288,17 @@ onCriticalClick(event: Event) {
307
288
  }
308
289
  ```
309
290
 
291
+ **other Event decorators**
292
+ - addEventListenerDelegateLightDom
293
+ - addEventListenerDelegateShadowDom
294
+ - addEventListenerDelegateAllDom
295
+ - addEventListenerDelegate
296
+ - addEventListenerThis
297
+ - addEventListenerAppHost
298
+ - addEventListenerWindow
299
+ - addEventListenerDocument
300
+
301
+
310
302
  #### @emitCustomEvent
311
303
  Emit custom events with data.
312
304
 
@@ -390,7 +382,7 @@ listItems?: HTMLLIElement[];
390
382
  ```
391
383
 
392
384
  #### @queryThis
393
- Query the component element itself.
385
+ Query the component element itself. == this
394
386
 
395
387
  ```typescript
396
388
  @queryThis
@@ -401,29 +393,17 @@ printTag() {
401
393
  }
402
394
  ```
403
395
 
404
- #### @queryAllThis
405
- Query all direct children of the component.
406
-
407
- ```typescript
408
- @queryAllThis
409
- children?: HTMLElement[];
410
-
411
- getChildCount() {
412
- return this.children?.length ?? 0;
413
- }
414
- ```
415
-
416
396
  ### 6. **Attribute Binding**
417
397
 
418
398
  #### @attribute
419
399
  Bind HTML attributes to properties (automatic sync).
420
400
 
421
401
  ```typescript
422
- @attribute
423
- width: string = '100px';
402
+ @attributeThis
403
+ width: string = '100px'; // Bind to this.width
424
404
 
425
405
  @attribute('data-id')
426
- resourceId: string = '';
406
+ resourceId: string; // element attribute first
427
407
  ```
428
408
 
429
409
  #### @attributeThis
@@ -431,7 +411,7 @@ Bind attributes on host element itself.
431
411
 
432
412
  ```typescript
433
413
  @attributeThis('product-id')
434
- productId: string = '';
414
+ productId?: string;
435
415
 
436
416
  @onInitialize
437
417
  onconstructor() {
@@ -496,321 +476,6 @@ SWC supports two types of expression syntax for dynamic value evaluation:
496
476
 
497
477
  ---
498
478
 
499
- #### 8.1 **SwcChoose - Multi-Condition Rendering**
500
-
501
- Switch-case style conditional rendering with `swc-when` and `swc-otherwise` sub-templates.
502
-
503
- ```typescript
504
- // Component with conditional rendering logic
505
- @elementDefine('status-display')
506
- class StatusDisplay extends HTMLElement {
507
- @attributeThis('status')
508
- status: string = 'pending';
509
-
510
- @setProperty('#status-template', 'value')
511
- getStatus() {
512
- return this.status;
513
- }
514
-
515
- @onConnectedInnerHtml
516
- render() {
517
- return `
518
- <template id="status-template" is="swc-choose">
519
- <template is="swc-when" test="$value === 'pending'">
520
- <div style="color: orange;">⏳ Processing...</div>
521
- </template>
522
-
523
- <template is="swc-when" test="$value === 'success'">
524
- <div style="color: green;">✓ Completed</div>
525
- </template>
526
-
527
- <template is="swc-when" test="$value === 'error'">
528
- <div style="color: red;">✗ Failed</div>
529
- </template>
530
-
531
- <!-- Fallback -->
532
- <template is="swc-otherwise">
533
- <div style="color: gray;">Unknown status</div>
534
- </template>
535
- </template>
536
- `;
537
- }
538
- }
539
- ```
540
-
541
- **Expression Features:**
542
- - `$value` contains the value passed to `swc-choose`
543
- - `skip-if-same` attribute prevents re-render when same template selected
544
- - **Attribute substitution with `{{= }}`**: `attribute-name="{{= expression }}"` automatically evaluated
545
-
546
- **Attribute Substitution Example ({{= }} usage):**
547
- ```html
548
- <template is="swc-choose">
549
- <template is="swc-when" test="$value?.type === 'user'">
550
- <user-card
551
- data-username="{{= $value?.name }}"
552
- data-email="{{= $value?.email }}"
553
- data-id="{{= $value?.id }}"
554
- ></user-card>
555
- </template>
556
-
557
- <template is="swc-when" value="$value?.type === 'product'">
558
- <product-card
559
- data-product-name="{{= $value?.title }}"
560
- data-price="{{= $value?.price }}"
561
- ></product-card>
562
- </template>
563
- </template>
564
- ```
565
-
566
- ---
567
-
568
- #### 8.2 **SwcIf - Binary Conditional**
569
-
570
- If-then-else rendering with optional `swc-default` fallback.
571
-
572
- ```typescript
573
- @elementDefine('user-profile')
574
- class UserProfile extends HTMLElement {
575
- private isLoggedIn = false;
576
- private userData = { userName: 'Alice', userId: 123 };
577
-
578
- @setProperty('#content', 'value')
579
- checkAuth() {
580
- return this.isLoggedIn;
581
- }
582
-
583
- @onConnectedInnerHtml
584
- render() {
585
- return `
586
- <!-- True condition: renders main template using {{ }} -->
587
- <template id="content" is="swc-if" value="{{ $host.isLoggedIn }}">
588
- <!-- Attribute substitution with {{= }} expressions -->
589
- <user-card
590
- data-username="{{= $host.userData.userName }}"
591
- data-userid="{{= $host.userData.userId }}"
592
- ></user-card>
593
- <div>
594
- <h2>Welcome, {{ $host.userData.userName }}</h2>
595
- <button on-click="logout">Logout</button>
596
- </div>
597
-
598
- <!-- Fallback template: renders if condition is false -->
599
- <template is="swc-default">
600
- <div>
601
- <p>Please log in</p>
602
- <button on-click="login">Login</button>
603
- </div>
604
- </template>
605
- </template>
606
- `;
607
- }
608
- }
609
- ```
610
-
611
- **Expression Features:**
612
- - Binary true/false logic with `{{ }} condition`
613
- - Main template renders when `value` is truthy
614
- - `swc-default` sub-template renders when value is falsy
615
- - Dynamic attribute substitution with `{{= }}` supported
616
- - Access `$host`, `$value`, and other context variables
617
- - `{{= functionCall() }}` executes functions and returns results for attributes
618
-
619
- ---
620
-
621
- #### 8.3 **SwcAsync - Promise/Loading State**
622
-
623
- Automatically handle async operations with loading, success, and error states.
624
-
625
- ```typescript
626
- @elementDefine('data-loader')
627
- class DataLoader extends HTMLElement {
628
- private data: any = null;
629
-
630
- async fetchData() {
631
- return new Promise((resolve, reject) => {
632
- setTimeout(() => {
633
- resolve({ id: 1, name: 'Sample Data', description: 'API response' });
634
- }, 2000);
635
- });
636
- }
637
-
638
- @setProperty('#async-content', 'value')
639
- loadData() {
640
- return this.fetchData();
641
- }
642
-
643
- @onConnectedInnerHtml
644
- render() {
645
- return `
646
- <template id="async-content" is="swc-async" value="{{= $host.fetchData() }}">
647
- <!-- Loading State: Shows while Promise is pending -->
648
- <template is="swc-loading">
649
- <div>🔄 Loading data...</div>
650
- </template>
651
-
652
- <!-- Success State: Shows when Promise resolves -->
653
- <!-- Using {{= }} to extract data from resolved Promise -->
654
- <template is="swc-success">
655
- <data-card
656
- data-id="{{= $value.id }}"
657
- data-name="{{= $value.name }}"
658
- ></data-card>
659
- <div>
660
- <p>Data ID: {{ $value.id }}</p>
661
- <p>Data Name: {{ $value.name }}</p>
662
- <p>Description: {{= $value.description }}</p>
663
- </div>
664
- </template>
665
-
666
- <!-- Error State: Shows if Promise rejects -->
667
- <template is="swc-error">
668
- <div style="color: red;">❌ Failed to load data</div>
669
- </template>
670
- </template>
671
- `;
672
- }
673
- }
674
- ```
675
-
676
- **Expression Features:**
677
- - Promise lifecycle management with `{{ }} conditions`
678
- - `{{= $host.fetchData() }}` - function call expression that executes and returns Promise
679
- - `{{= $value.propertyName }}` - extract properties from resolved value
680
- - `swc-loading` - displays during pending state
681
- - `swc-success` - displays on successful resolution, `$value` contains resolved result
682
- - `swc-error` - displays on Promise rejection, `$value` contains error
683
- - Dynamic attribute substitution with `{{= }}` in all states
684
- - `on-clone-node` and `on-clone-nodes` callbacks for DOM manipulation
685
-
686
- ---
687
-
688
- #### 8.4 **SwcLoop - List Rendering**
689
-
690
- Iterate over arrays and render templates for each item.
691
-
692
- ```typescript
693
- @elementDefine('product-list')
694
- class ProductList extends HTMLElement {
695
- private products = [
696
- { id: 1, name: 'Laptop', price: 1200, category: 'electronics' },
697
- { id: 2, name: 'Phone', price: 800, category: 'electronics' },
698
- { id: 3, name: 'Tablet', price: 500, category: 'electronics' }
699
- ];
700
-
701
- @setProperty('#products-list', 'value')
702
- getProducts() {
703
- return this.products;
704
- }
705
-
706
- @onConnectedInnerHtml
707
- render() {
708
- return `
709
- <template id="products-list" is="swc-loop" value="{{= $host.products }}">
710
- <!-- Loop iteration with {{ }} for display and {{= }} for attributes -->
711
- <div style="margin: 10px; padding: 10px; border: 1px solid #ddd;">
712
- <!-- Using {{ }} for template content rendering -->
713
- <h3>{{ $item.name }}</h3>
714
- <p>Price: {{ $item.price }}</p>
715
- <p>ID: {{ $item.id }} (Index: {{ $index }})</p>
716
-
717
- <!-- Using {{= }} for dynamic attribute substitution -->
718
- <product-card
719
- data-product-id="{{= $item.id }}"
720
- data-product-name="{{= $item.name }}"
721
- data-product-price="{{= $item.price }}"
722
- data-product-category="{{= $item.category }}"
723
- ></product-card>
724
-
725
- <!-- Computed expressions with {{= }} -->
726
- <button data-id="{{= $item.id }}" data-price="{{= $item.price }}">
727
- Add to Cart - {{ $item.price }}
728
- </button>
729
- </div>
730
-
731
- <!-- Empty fallback: renders when array is empty -->
732
- <template is="swc-default">
733
- <p>No products available</p>
734
- </template>
735
- </template>
736
- `;
737
- }
738
- }
739
- ```
740
-
741
- **Context Variables (Available in loop):**
742
- - `$item` - current item in iteration
743
- - `$index` - zero-based index (0, 1, 2, ...)
744
- - `$value` - entire array being iterated
745
- - `$nodes` - cloned DOM nodes
746
- - `$elements` - cloned HTML elements
747
- - `$firstElement` - first element in cloned nodes
748
-
749
- **Expression Features:**
750
- - `{{= $host.products }}` - function call expression that returns the array to iterate
751
- - `{{ $item.propertyName }}` - display item properties using standard `{{ }}`
752
- - `{{= $item.propertyName }}` - extract item properties for attributes using `{{= }}`
753
- - `{{= computedValue }}` - compute values in attributes (e.g., calculations, method calls)
754
- - `swc-default` fallback renders when array is empty
755
- - All cloned attributes support `{{ }}` and `{{= }}` substitution
756
- - `on-clone-node` callback fires for each cloned node
757
- - `on-clone-nodes` callback fires after all nodes cloned
758
-
759
- **Common Patterns:**
760
- ```html
761
- <!-- Template functions with {{= }} -->
762
- <template is="swc-loop" value="{{= filterProducts($host.products) }}">
763
- <!-- Dynamic calculations -->
764
- <span>Total: {{= $item.price * $item.quantity }}</span>
765
-
766
- <!-- Conditional attributes -->
767
- <div class="{{= $item.inStock ? 'available' : 'unavailable' }}"></div>
768
-
769
- <!-- Method calls as attributes -->
770
- <button data-formatted="{{= formatPrice($item.price) }}">
771
- Buy - {{ formatPrice($item.price) }}
772
- </button>
773
- </template>
774
- ```
775
-
776
- **Advanced: replace-wrap-start replace-wrap-end for Custom Expression Syntax**
777
-
778
- Override default `{{ }}` and `{{= }}` syntax with custom wrappers:
779
-
780
- ```typescript
781
- @elementDefine('custom-loop')
782
- class CustomLoop extends HTMLElement {
783
- private items = [{ id: 1, name: 'Item 1' }];
784
-
785
- @onConnectedInnerHtml
786
- render() {
787
- return `
788
- <!-- Using custom wrapper syntax [(= ... )] instead of {{= ... }} -->
789
- <template id="items" is="swc-loop" replace-wrap-start="[(" replace-wrap-end=")]" value="{{= $host.items }}">
790
- <div>
791
- <p>Name: [( $item.name )]</p>
792
- <button data-id="[( $item.id )]">Click me</button>
793
- </div>
794
- </template>
795
- `;
796
- }
797
- }
798
- ```
799
-
800
- **replace-wrap attribute options:**
801
- - Change expression wrapper from default `{#{ }#}` to custom pattern
802
- - Supported on: `SwcLoop`, `SwcChoose`, `SwcIf`, `SwcAsync`, `register()` directives
803
-
804
- ---
805
-
806
- **Benefits:**
807
- - ✅ **No imperative route methods** - routes are declarative templates
808
- - ✅ **Automatic re-rendering** - attributes like `user-id` update automatically
809
- - ✅ **Performance optimization** - use `skip-if-same` on templates to prevent re-renders
810
- - ✅ **Dynamic path parameters** - use `{{= $value?.pathData?.id }}` syntax to inject route params with `{{= }}`
811
- - ✅ **Cleaner DX** - single unified routing pattern
812
- - ✅ **Full expression support** - use `{{= }}` for complex parameter transformations
813
-
814
479
  ### 9. **Component Communication - Message Bus**
815
480
 
816
481
  SWC provides a powerful message bus system for inter-component communication through SwcApp. Components can publish and subscribe to typed messages while connected.
@@ -821,7 +486,7 @@ Subscribe to messages while component is connected to DOM.
821
486
  ```typescript
822
487
  @elementDefine('notification-panel')
823
488
  class NotificationPanel extends HTMLElement {
824
- @subscribeSwcAppMessageWhileConnected()
489
+ @subscribeSwcAppMessageWhileConnected
825
490
  onAnyMessage(message: SwcAppMessage) {
826
491
  console.log('Received message:', message);
827
492
  }
@@ -948,7 +613,7 @@ import {
948
613
  ```typescript
949
614
  // index.ts
950
615
  import 'reflect-metadata';
951
- import { SwcAppInterface, defineSwcAppAll } from '@dooboostore/simple-web-component';
616
+ import { defineSwcAppBody, SwcAppInterface, defineSwcAppAll } from '@dooboostore/simple-web-component';
952
617
  import bootFactory from './bootFactory';
953
618
 
954
619
  const w = window;
@@ -957,10 +622,8 @@ w.document.addEventListener('DOMContentLoaded', async () => {
957
622
  const container = Symbol('app');
958
623
 
959
624
  // Initialize services and components
960
- bootFactory(w, container);
625
+ await defineSwcAppBody(w);
961
626
 
962
- // Register all SwcApp variants
963
- await defineSwcAppAll(w);
964
627
 
965
628
  // Get app root element
966
629
  const appElement = w.document.querySelector('#app') as SwcAppInterface;
@@ -970,6 +633,7 @@ w.document.addEventListener('DOMContentLoaded', async () => {
970
633
  path: '/',
971
634
  routeType: 'path',
972
635
  container: container,
636
+ onStartedLazyDefineComponent: [yourComponentFactory1, yourComponentFactor2],
973
637
  window: w,
974
638
  onEngineStarted: () => {
975
639
  console.log('🚀 Application started successfully');
@@ -979,64 +643,41 @@ w.document.addEventListener('DOMContentLoaded', async () => {
979
643
  });
980
644
  ```
981
645
 
982
- #### SwcAppMixin - Reusable Component Logic
983
-
984
- The `SwcAppMixin` extracts all SwcApp functionality into a reusable mixin that can be applied to any HTMLElement type:
985
-
986
- ```typescript
987
- import { SwcAppMixin } from '@dooboostore/simple-web-component';
988
- import { elementDefine } from '@dooboostore/simple-web-component';
989
-
990
- // Create custom SwcApp variant extending HTMLDivElement
991
- @elementDefine('custom-app', { window: w, extends: 'div' })
992
- class CustomApp extends SwcAppMixin(w.HTMLDivElement) implements SwcAppInterface {
993
- // All SwcApp functionality inherited from mixin
994
- // Add custom logic here if needed
995
- }
996
- ```
997
-
998
- #### SwcAppMixin Features
999
-
1000
- The mixin provides:
1001
- - **Lifecycle Management**: `connectedCallback`, `disconnectedCallback` with parent class support
1002
- - **Routing**: `routing(path)`, `back()`, `forward()`, `reload()`
1003
- - **Message Bus**: `publishMessage()` for inter-component communication
1004
- - **Route Subscriptions**: Automatic route change handling for connected components
1005
- - **SSR Support**: `isSSR()`, `setSSRAttribute()`, `removeSSRAttribute()` utilities
1006
- - **DI Integration**: Full dependency injection support via `@onInitialize`
1007
-
1008
646
  #### Factory Pattern - Component Registration
1009
647
 
1010
648
  ```typescript
1011
649
  // Component factory
650
+ import {defineSwcApp} from "./SwcApp";
651
+
1012
652
  export default (w: Window) => {
1013
653
  const tagName = 'my-component';
1014
654
  const existing = w.customElements.get(tagName);
1015
655
  if (existing) return tagName;
1016
656
 
1017
- @elementDefine(tagName, { window: w })
657
+ @elementDefine(tagName, {window: w})
1018
658
  class MyComponent extends w.HTMLElement {
1019
659
  @onInitialize
1020
660
  onconstructor(service: MyService) {
1021
661
  this.service = service;
1022
662
  }
1023
663
  }
1024
-
664
+
1025
665
  return tagName;
1026
666
  };
1027
667
 
1028
668
  // Boot factory
1029
669
  export default (w: Window, container: symbol) => {
1030
670
  serviceFactories.forEach(s => s(container));
1031
- register(w, [...pageFactories, ...componentFactories]);
1032
671
  };
1033
672
 
1034
673
  // Entry point
1035
674
  const container = Symbol('app');
1036
- bootFactory(w, container);
675
+ await defineSwcAppBody(w)
676
+ const appElement = w.document.querySelector('#app') as SwcAppInterface;
1037
677
  appElement.connect({
1038
678
  container,
1039
679
  window: w,
680
+ onStartedLazyDefineComponent: [...pageFactories, ...componentFactories],
1040
681
  onEngineStarted: () => {
1041
682
  appElement.innerHTML = '<root-router></root-router>';
1042
683
  }
@@ -1048,487 +689,62 @@ Factory-based component registration with explicit DI.
1048
689
 
1049
690
  ```typescript
1050
691
  // Component factory
692
+ import {SwcUtils, createElement, CreateElementConfig} from '@dooboostore/simple-web-component';
693
+ const tagName = 'my-component';
694
+ export interface MyComponent extends HTMLElement {
695
+ value: string;
696
+ }
697
+ export const MyComponent = (w: Window|Document, data?: CreateElementConfig) => {
698
+ return createElement<HTMLElement>(w, tagName, data);
699
+ };
1051
700
  export default (w: Window) => {
1052
- const tagName = 'my-component';
1053
701
  const existing = w.customElements.get(tagName);
1054
- if (existing) return tagName;
702
+ if (existing) return existing;
1055
703
 
1056
704
  @elementDefine(tagName, { window: w })
1057
- class MyComponent extends w.HTMLElement {
705
+ class MyComponentImp extends w.HTMLElement implements MyComponent{
706
+ value: string = 'value';
1058
707
  @onInitialize
1059
708
  onconstructor(service: MyService) {
1060
709
  this.service = service;
1061
710
  }
1062
711
  }
1063
-
1064
- return tagName;
1065
- };
1066
-
1067
- // Boot factory
1068
- export default (w: Window, container: symbol) => {
1069
- serviceFactories.forEach(s => s(container));
1070
- register(w, [...pageFactories, ...componentFactories]);
712
+ return w.customElements.whenDefined(swcAppTagName);
1071
713
  };
1072
714
 
1073
- // Entry point
1074
- const container = Symbol('app');
1075
- bootFactory(w, container);
1076
- appElement.connect({
1077
- container,
1078
- window: w,
1079
- onEngineStarted: () => {
1080
- appElement.innerHTML = '<root-router></root-router>';
1081
- }
1082
- });
1083
715
  ```
1084
-
1085
- ### 12. **Quickstart - Basic SPA Setup**
1086
-
1087
- Complete example of setting up a production SPA with routing, services, and components.
1088
-
1089
- #### Step 1. HTML Entry Point
1090
- ```html
1091
- <!DOCTYPE html>
1092
- <html>
1093
- <head>
1094
- <meta charset="UTF-8">
1095
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1096
- <title>My SPA</title>
1097
- <!-- Web Components polyfill for older browsers -->
1098
- <script src="https://unpkg.com/@ungap/custom-elements"></script>
1099
- </head>
1100
- <!-- Use is="swc-app-body" for semantic HTML root -->
1101
- <body id="app" is="swc-app-body">
1102
- <!-- Root router will render pages here -->
1103
- <root-router></root-router>
1104
- </body>
1105
- <script src="bundle.js"></script>
1106
- </html>
1107
- ```
1108
-
1109
- #### Step 2. Services (Dependency Injection)
1110
- ```typescript
1111
- // services/UserService.ts
1112
- import { Sim } from '@dooboostore/simple-boot';
1113
- import { ConstructorType } from '@dooboostore/core';
1114
-
1115
- export namespace UserService {
1116
- export const SYMBOL = Symbol('UserService');
1117
-
1118
- export interface User {
1119
- id: number;
1120
- name: string;
1121
- email: string;
1122
- }
1123
-
1124
- const users: User[] = [
1125
- { id: 1, name: 'Alice', email: 'alice@example.com' },
1126
- { id: 2, name: 'Bob', email: 'bob@example.com' }
1127
- ];
1128
- }
1129
-
1130
- export interface UserService {
1131
- getUser(id: number): UserService.User | undefined;
1132
- getAllUsers(): UserService.User[];
1133
- }
1134
-
1135
- // Factory function: accepts container and returns service class
1136
- export default (container: symbol): ConstructorType<any> => {
1137
- @Sim({ symbol: UserService.SYMBOL, container: container })
1138
- class UserServiceImpl implements UserService {
1139
- getUser(id: number) {
1140
- return UserService.users.find(u => u.id === id);
1141
- }
1142
-
1143
- getAllUsers() {
1144
- return [...UserService.users];
1145
- }
1146
- }
1147
-
1148
- return UserServiceImpl;
1149
- };
1150
- ```
1151
-
1152
- ```typescript
1153
- // services/index.ts
1154
- import userServiceFactory from './UserService';
1155
-
1156
- export const serviceFactories = [userServiceFactory];
1157
- ```
1158
-
1159
- #### Step 3. Router Configuration (Declarative with swc-choose)
1160
- ```typescript
1161
- // pages/RootRouter.ts
1162
- import { elementDefine, subscribeSwcAppRouteChangeWhileConnected, setProperty, onConnectedInnerHtml, onInitialize } from '@dooboostore/simple-web-component';
1163
- import { Router, RouterEventType } from '@dooboostore/core-web';
1164
-
1165
- const rootRouterFactory = (w: Window) => {
1166
- const tagName = 'root-router';
1167
- const existing = w.customElements.get(tagName);
1168
- if (existing) return tagName;
1169
-
1170
- @elementDefine(tagName, { window: w })
1171
- class RootRouter extends w.HTMLElement {
1172
- private router: Router;
1173
-
1174
- @onInitialize
1175
- onconstructor(router: Router) {
1176
- this.router = router;
1177
- }
1178
-
1179
- @setProperty('#router', 'value')
1180
- @subscribeSwcAppRouteChangeWhileConnected(['/', '/users', '/users/{id}'])
1181
- routeChanged(route: RouterEventType) {
1182
- return route;
1183
- }
1184
-
1185
- navigate(path: string): void {
1186
- this.router?.go(path);
1187
- }
1188
-
1189
- @onConnectedInnerHtml
1190
- render() {
1191
- return `
1192
- <template id="router" is="swc-choose">
1193
- <!-- Home Page -->
1194
- <template is="swc-when" test="['', '/'].includes($value?.path)">
1195
- <home-page/>
1196
- </template>
1197
-
1198
- <!-- Users List -->
1199
- <template is="swc-when" test="$value?.path === '/users'">
1200
- <users-list-page/>
1201
- </template>
1202
-
1203
- <!-- User Detail -->
1204
- <template is="swc-when" test="$value?.path.startsWith('/users/')">
1205
- <user-detail-page user-id="{{= $value?.pathData?.id}}"/>
1206
- </template>
1207
-
1208
- <!-- Not Found -->
1209
- <template is="swc-otherwise">
1210
- <not-found-page/>
1211
- </template>
1212
- </template>
1213
- `;
1214
- }
1215
- }
1216
-
1217
- return tagName;
1218
- };
1219
-
1220
- export default rootRouterFactory;
1221
- ```
1222
-
1223
- #### Step 4. Page Components
1224
- ```typescript
1225
- // pages/HomePage.ts
1226
- import { elementDefine, onConnectedInnerHtml } from '@dooboostore/simple-web-component';
1227
-
1228
- const HomePage = (w: Window) => {
1229
- const tagName = 'home-page';
1230
- const existing = w.customElements.get(tagName);
1231
- if (existing) return tagName;
1232
-
1233
- @elementDefine(tagName, { window: w })
1234
- class HomePage extends w.HTMLElement {
1235
- @onConnectedInnerHtml({ useShadow: true })
1236
- render() {
1237
- return `
1238
- <style>
1239
- :host { display: block; padding: 20px; }
1240
- h1 { color: #333; }
1241
- a { color: #0066cc; text-decoration: none; margin-right: 20px; }
1242
- </style>
1243
- <h1>Welcome to My SPA</h1>
1244
- <nav>
1245
- <a href="/users">View All Users</a>
1246
- </nav>
1247
- `;
1248
- }
1249
- }
1250
-
1251
- return tagName;
1252
- };
1253
-
1254
- export default HomePage;
1255
- ```
1256
-
1257
- ```typescript
1258
- // pages/UsersListPage.ts
1259
- import { elementDefine, onConnectedInnerHtml, onConnectedBefore } from '@dooboostore/simple-web-component';
1260
- import { Inject } from '@dooboostore/simple-boot';
1261
- import { UserService } from '../services/UserService';
1262
-
1263
- const UsersListPage = (w: Window) => {
1264
- const tagName = 'users-list-page';
1265
- const existing = w.customElements.get(tagName);
1266
- if (existing) return tagName;
1267
-
1268
- @elementDefine(tagName, { window: w })
1269
- class UsersListPage extends w.HTMLElement {
1270
- private users: any[] = [];
1271
-
1272
- @onConnectedBefore
1273
- onconstructor(@Inject({ symbol: UserService.SYMBOL }) userService: UserService) {
1274
- this.users = userService.getAllUsers();
1275
- }
1276
-
1277
- @onConnectedInnerHtml({ useShadow: true })
1278
- render() {
1279
- const usersList = this.users
1280
- .map(u => `<li><a href="/users/${u.id}">${u.name}</a></li>`)
1281
- .join('');
1282
-
1283
- return `
1284
- <style>
1285
- :host { display: block; padding: 20px; }
1286
- h1 { color: #333; }
1287
- ul { list-style: none; padding: 0; }
1288
- li { margin: 10px 0; }
1289
- a { color: #0066cc; text-decoration: none; }
1290
- </style>
1291
- <h1>Users</h1>
1292
- <ul>${usersList}</ul>
1293
- <a href="/">Back to Home</a>
1294
- `;
1295
- }
1296
- }
1297
-
1298
- return tagName;
1299
- };
1300
-
1301
- export default UsersListPage;
1302
- ```
1303
-
1304
- #### Step 4-1. Reusable Components
1305
- ```typescript
1306
- // components/UserCard.ts
1307
- import { elementDefine, onConnectedInnerHtml, attributeThis } from '@dooboostore/simple-web-component';
1308
-
1309
- const UserCard = (w: Window) => {
1310
- const tagName = 'user-card';
1311
- const existing = w.customElements.get(tagName);
1312
- if (existing) return tagName;
1313
-
1314
- @elementDefine(tagName, { window: w })
1315
- class UserCard extends w.HTMLElement {
1316
- @attributeThis('data-username')
1317
- username: string;
1318
-
1319
- @attributeThis('data-email')
1320
- email: string;
1321
-
1322
- @onConnectedInnerHtml({ useShadow: true })
1323
- render() {
1324
- return `
1325
- <style>
1326
- :host { display: block; }
1327
- .card { border: 1px solid #ddd; border-radius: 4px; padding: 12px; }
1328
- .name { font-weight: bold; font-size: 14px; }
1329
- .email { color: #666; font-size: 12px; }
1330
- </style>
1331
- <div class="card">
1332
- <div class="name">${this.username}</div>
1333
- <div class="email">${this.email}</div>
1334
- </div>
1335
- `;
1336
- }
1337
- }
1338
-
1339
- return tagName;
1340
- };
1341
-
1342
- export default UserCard;
1343
- ```
1344
-
1345
- #### Step 5. Export Factories
1346
-
1347
- **services/index.ts** - Export all service factories
1348
- ```typescript
1349
- // services/index.ts
1350
- import userServiceFactory from './UserService';
1351
-
1352
- export const serviceFactories = [userServiceFactory];
1353
- ```
1354
-
1355
- **components/index.ts** - Export all component factories
1356
- ```typescript
1357
- // components/index.ts
1358
- import UserCard from './UserCard';
1359
-
1360
- export const componentFactories = [
1361
- UserCard,
1362
- ];
1363
- ```
1364
-
1365
- **pages/index.ts** - Export all page factories with router
1366
- ```typescript
1367
- // pages/index.ts
1368
- import rootRouterFactory from './RootRouter';
1369
- import HomePage from './HomePage';
1370
- import UsersListPage from './UsersListPage';
1371
- import UserDetailPage from './UserDetailPage';
1372
-
1373
- export const pageFactories = [
1374
- rootRouterFactory, // Router first
1375
- HomePage,
1376
- UsersListPage,
1377
- UserDetailPage
1378
- ];
1379
- ```
1380
-
1381
- #### Step 6. Application Bootstrap
1382
- ```typescript
1383
- // bootFactory.ts
1384
- import { register } from '@dooboostore/simple-web-component';
1385
- import { serviceFactories } from './services';
1386
- import { componentFactories } from './components';
1387
- import { pageFactories } from './pages';
1388
-
1389
- export default (w: Window, container: symbol) => {
1390
- // Initialize services with container (dependency injection)
1391
- // Each factory receives the container symbol and registers its service in the DI container
1392
- serviceFactories.forEach(serviceFactory => serviceFactory(container));
1393
-
1394
- // Register pages and components
1395
- register(w, [...pageFactories, ...componentFactories]);
1396
- };
1397
- ```
1398
-
1399
- #### Step 7. Application Entry Point
1400
- ```typescript
1401
- // index.ts
1402
- import 'reflect-metadata';
1403
- import { SwcAppInterface, defineSwcAppAll } from '@dooboostore/simple-web-component';
1404
- import bootFactory from './bootFactory';
1405
-
1406
- const w = window;
1407
-
1408
- w.document.addEventListener('DOMContentLoaded', async () => {
1409
- const container = Symbol('app');
1410
-
1411
- // Initialize services and components
1412
- bootFactory(w, container);
1413
-
1414
- // Register all SwcApp variants (swc-app, swc-app-body, swc-app-div, etc.)
1415
- await defineSwcAppAll(w);
1416
-
1417
- // Get app root element
1418
- const appElement = w.document.querySelector('#app') as SwcAppInterface;
1419
-
1420
- if (appElement && typeof appElement.connect === 'function') {
1421
- // Connect SPA with routing and DI
1422
- appElement.connect({
1423
- path: '/',
1424
- routeType: 'path',
1425
- container: container,
1426
- window: w,
1427
- onEngineStarted: () => {
1428
- console.log('🚀 Application started successfully');
1429
- // Root router automatically initialized via @elementDefine
1430
- }
1431
- });
1432
- } else {
1433
- console.error('Failed to initialize SPA');
1434
- }
1435
- });
1436
- ```ow;
1437
-
1438
- w.document.addEventListener('DOMContentLoaded', async () => {
1439
- const container = Symbol('app');
1440
-
1441
- // Initialize services and components
1442
- bootFactory(w, container);
1443
-
1444
- // Wait for customized built-in element to be defined
1445
- await w.customElements.whenDefined('swc-app-body');
1446
-
1447
- // Get app root element
1448
- const appElement = w.document.querySelector('#app') as SwcAppInterface;
1449
-
1450
- if (appElement && typeof appElement.connect === 'function') {
1451
- // Connect SPA with routing and DI
1452
- appElement.connect({
1453
- path: '/',
1454
- routeType: 'path',
1455
- container: container,
1456
- window: w,
1457
- onEngineStarted: () => {
1458
- console.log('🚀 Application started successfully');
1459
- // Root router automatically initialized via @elementDefine
1460
- }
1461
- });
1462
- } else {
1463
- console.error('Failed to initialize SPA');
1464
- }
1465
- });
1466
- ```
1467
-
1468
- #### Resulting Application Structure
1469
- ```
1470
- src/
1471
- ├── index.ts # Entry point
1472
- ├── index.html # HTML root with <root-router>
1473
- ├── bootFactory.ts # Bootstrap services & components via register()
1474
- ├── services/
1475
- │ ├── UserService.ts # Service factory (export default)
1476
- │ └── index.ts # Export serviceFactories
1477
- ├── pages/
1478
- │ ├── RootRouter.ts # Router factory (export default)
1479
- │ ├── HomePage.ts # Page factory (export default)
1480
- │ ├── UsersListPage.ts # Page factory (export default)
1481
- │ ├── UserDetailPage.ts # Page factory (export default)
1482
- │ └── index.ts # Export pageFactories
1483
- └── components/
1484
- ├── UserCard.ts # Component factory (export default)
1485
- └── index.ts # Export componentFactories
1486
- ```
1487
-
1488
- **Key Flow:**
1489
- 1. HTML loads → `<root-router>` element already in DOM
1490
- 2. `index.ts` executes → calls `bootFactory`
1491
- 3. `bootFactory` registers services and components (including `rootRouterFactory`)
1492
- 4. App waits for `swc-app-body` to be defined via `defineSwcAppAll()`
1493
- 5. `appElement.connect()` initializes routing & DI
1494
- 6. `<root-router>` becomes active with `@subscribeSwcAppRouteChangeWhileConnected` + `swc-choose` template
1495
- 7. Route changes automatically trigger `swc-choose` re-evaluation and template re-rendering
1496
- 8. Template attributes like `user-id="{{= $value?.pathData?.id}}"` are dynamically populated with route params
1497
- 9. All components have access to injected services via `@onInitialize`
1498
-
1499
-
1500
716
  ---
1501
717
 
1502
718
  ## ⚠️ Critical Rules
1503
719
 
1504
720
  ### DO NOT Use @Sim on Web Components
1505
- `@Sim` is for **Services only**. Web Components should use `@elementDefine`.
721
+ `@sim` is for **Services only**. Web Components should use `@elementDefine`.
1506
722
 
1507
723
  ```typescript
1508
724
  // ✅ CORRECT
1509
- @Sim
725
+ @sim
1510
726
  export class UserService { }
1511
727
 
1512
728
  @elementDefine(tagName, { window: w })
1513
729
  class UserWidget extends w.HTMLElement { }
1514
730
 
1515
731
  // ❌ WRONG
1516
- @Sim
732
+ @sim
1517
733
  @elementDefine(tagName, { window: w })
1518
734
  class UserWidget extends w.HTMLElement { }
1519
735
  ```
1520
736
 
1521
- ### Factory Always Returns tagName (String)
737
+ ### Factory Always Returns
1522
738
  ```typescript
1523
739
  export default (w: Window) => {
1524
740
  const tagName = 'my-element';
1525
741
  const existing = w.customElements.get(tagName);
1526
- if (existing) return tagName; // ← Return string!
742
+ if (existing) return existing;
1527
743
 
1528
744
  @elementDefine(tagName, { window: w })
1529
745
  class MyElement extends w.HTMLElement { }
1530
746
 
1531
- return tagName; // ← Always return tagName, never class
747
+ return existing;
1532
748
  };
1533
749
  ```
1534
750
 
@@ -1536,7 +752,7 @@ export default (w: Window) => {
1536
752
  ```typescript
1537
753
  // ✅ CORRECT
1538
754
  @onInitialize
1539
- onconstructor(@Inject({ symbol: Service.SYMBOL }) service: Service) {
755
+ onconstructor(@inject(Service.SYMBOL) service: Service) {
1540
756
  this.service = service;
1541
757
  }
1542
758
 
@@ -1548,19 +764,20 @@ constructor(private service: Service) { super(); } // Web Components can't have
1548
764
 
1549
765
  ## 📚 Examples
1550
766
 
1551
- - **[Commerce (E-Commerce SPA)](./examples/commerce)** - Full shopping cart example
1552
- - **[Stock (Market Dashboard)](./examples/stock)** - Real-time data with routing
1553
- - **[Accommodation (Reference Pattern)](./examples/accommodation)** - Standard setup pattern
767
+ - **[Commerce (E-Commerce SPA)](https://github.com/dooboostore-develop/packages/tree/main/%40dooboostore/simple-web-component/examples/commerce)** - Full shopping cart example
768
+ - **[Stock (Market Dashboard)](https://github.com/dooboostore-develop/packages/tree/main/%40dooboostore/simple-web-component/examples/stock)** - Real-time data with routing
769
+ - **[Accommodation (Reference Pattern)](https://github.com/dooboostore-develop/packages/tree/main/%40dooboostore/simple-web-component/examples/accommodation)** - Standard setup pattern
1554
770
 
1555
771
  ---
1556
772
 
1557
773
  ## 🔗 Related Packages
1558
774
 
1559
- - **[@dooboostore/simple-boot](../simple-boot)** - DI & AOP Container
1560
- - **[@dooboostore/core-web](../core-web)** - Web Utilities & Router
1561
- - **[@dooboostore/dom-parser](../dom-parser)** - HTML Parsing & AST
775
+ - **[@dooboostore/simple-boot](https://github.com/dooboostore-develop/packages/tree/main/%40dooboostore/simple-boot)** - DI & AOP Container
776
+ - **[@dooboostore/core-web](https://github.com/dooboostore-develop/packages/tree/main/%40dooboostore/core-web)** - Web Utilities & Router
777
+ - **[@dooboostore/dom-parser](https://github.com/dooboostore-develop/packages/tree/main/%40dooboostore/dom-parser)** - HTML Parsing & AST
1562
778
 
1563
779
  ---
1564
780
 
1565
781
  ## 📄 License
1566
- MIT © 2024 dooboostore-develop
782
+ [MIT License](https://github.com/dooboostore-develop/packages/tree/main/%40dooboostore/simple-web-component/LICENSE.md)
783
+