@dooboostore/simple-web-component 1.0.31 → 1.0.33

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 (100) hide show
  1. package/README.md +280 -43
  2. package/dist/cjs/decorators/applyStyle.js +1 -1
  3. package/dist/cjs/decorators/applyStyle.js.map +2 -2
  4. package/dist/cjs/decorators/attribute.js +17 -1
  5. package/dist/cjs/decorators/attribute.js.map +2 -2
  6. package/dist/cjs/decorators/elementDefine.js +27 -10
  7. package/dist/cjs/decorators/elementDefine.js.map +3 -3
  8. package/dist/cjs/decorators/index.js +3 -1
  9. package/dist/cjs/decorators/index.js.map +2 -2
  10. package/dist/cjs/decorators/publishSwcAppMessage.js +86 -0
  11. package/dist/cjs/decorators/publishSwcAppMessage.js.map +7 -0
  12. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +62 -0
  13. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +7 -0
  14. package/dist/cjs/decorators/{subscribeSwcAppRouteChange.js → subscribeSwcAppRouteChangeWhileConnected.js} +16 -16
  15. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +7 -0
  16. package/dist/cjs/elements/SwcAppMixin.js +32 -3
  17. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  18. package/dist/cjs/elements/SwcAsync.js +69 -57
  19. package/dist/cjs/elements/SwcAsync.js.map +2 -2
  20. package/dist/cjs/elements/SwcChoose.js +66 -60
  21. package/dist/cjs/elements/SwcChoose.js.map +2 -2
  22. package/dist/cjs/elements/SwcIf.js +51 -66
  23. package/dist/cjs/elements/SwcIf.js.map +2 -2
  24. package/dist/cjs/elements/SwcLoop.js +58 -78
  25. package/dist/cjs/elements/SwcLoop.js.map +2 -2
  26. package/dist/cjs/elements/register.js +310 -335
  27. package/dist/cjs/elements/register.js.map +2 -2
  28. package/dist/cjs/types.js.map +1 -1
  29. package/dist/cjs/utils/Utils.js +7 -13
  30. package/dist/cjs/utils/Utils.js.map +2 -2
  31. package/dist/esm/decorators/applyStyle.js +1 -1
  32. package/dist/esm/decorators/applyStyle.js.map +2 -2
  33. package/dist/esm/decorators/attribute.js +18 -2
  34. package/dist/esm/decorators/attribute.js.map +2 -2
  35. package/dist/esm/decorators/elementDefine.js +25 -8
  36. package/dist/esm/decorators/elementDefine.js.map +3 -3
  37. package/dist/esm/decorators/index.js +3 -1
  38. package/dist/esm/decorators/index.js.map +2 -2
  39. package/dist/esm/decorators/publishSwcAppMessage.js +67 -0
  40. package/dist/esm/decorators/publishSwcAppMessage.js.map +7 -0
  41. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +43 -0
  42. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +7 -0
  43. package/dist/esm/decorators/{subscribeSwcAppRouteChange.js → subscribeSwcAppRouteChangeWhileConnected.js} +13 -13
  44. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +7 -0
  45. package/dist/esm/elements/SwcAppMixin.js +32 -3
  46. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  47. package/dist/esm/elements/SwcAsync.js +70 -58
  48. package/dist/esm/elements/SwcAsync.js.map +2 -2
  49. package/dist/esm/elements/SwcChoose.js +67 -61
  50. package/dist/esm/elements/SwcChoose.js.map +2 -2
  51. package/dist/esm/elements/SwcIf.js +52 -67
  52. package/dist/esm/elements/SwcIf.js.map +2 -2
  53. package/dist/esm/elements/SwcLoop.js +59 -79
  54. package/dist/esm/elements/SwcLoop.js.map +2 -2
  55. package/dist/esm/elements/register.js +239 -264
  56. package/dist/esm/elements/register.js.map +2 -2
  57. package/dist/esm/types.js.map +1 -1
  58. package/dist/esm/utils/Utils.js +7 -13
  59. package/dist/esm/utils/Utils.js.map +2 -2
  60. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +2804 -2498
  61. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  62. package/dist/types/decorators/attribute.d.ts.map +1 -1
  63. package/dist/types/decorators/elementDefine.d.ts +1 -0
  64. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  65. package/dist/types/decorators/index.d.ts +3 -1
  66. package/dist/types/decorators/index.d.ts.map +1 -1
  67. package/dist/types/decorators/publishSwcAppMessage.d.ts +13 -0
  68. package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -0
  69. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +16 -0
  70. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -0
  71. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +18 -0
  72. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -0
  73. package/dist/types/elements/SwcAppMixin.d.ts +3 -0
  74. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  75. package/dist/types/elements/register.d.ts.map +1 -1
  76. package/dist/types/types.d.ts +14 -1
  77. package/dist/types/types.d.ts.map +1 -1
  78. package/dist/types/utils/Utils.d.ts.map +1 -1
  79. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +2804 -2498
  80. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  81. package/package.json +4 -4
  82. package/src/decorators/applyStyle.ts +1 -1
  83. package/src/decorators/attribute.ts +35 -30
  84. package/src/decorators/elementDefine.ts +28 -8
  85. package/src/decorators/index.ts +3 -1
  86. package/src/decorators/publishSwcAppMessage.ts +100 -0
  87. package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +73 -0
  88. package/src/decorators/{subscribeSwcAppRouteChange.ts → subscribeSwcAppRouteChangeWhileConnected.ts} +19 -19
  89. package/src/elements/SwcAppMixin.ts +43 -4
  90. package/src/elements/SwcAsync.ts +75 -69
  91. package/src/elements/SwcChoose.ts +67 -80
  92. package/src/elements/SwcIf.ts +51 -76
  93. package/src/elements/SwcLoop.ts +56 -87
  94. package/src/elements/register.ts +235 -307
  95. package/src/types.ts +14 -1
  96. package/src/utils/Utils.ts +11 -17
  97. package/dist/cjs/decorators/subscribeSwcAppRouteChange.js.map +0 -7
  98. package/dist/esm/decorators/subscribeSwcAppRouteChange.js.map +0 -7
  99. package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts +0 -18
  100. package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts.map +0 -1
package/README.md CHANGED
@@ -251,6 +251,35 @@ onAppReady(router: Router) {
251
251
 
252
252
  Structural Directives allow declarative conditional rendering, list iteration, async handling, and routing with automatic attribute substitution and dynamic expressions.
253
253
 
254
+ #### 8.0 **Expression Syntax - Dynamic Evaluation**
255
+
256
+ SWC supports two types of expression syntax for dynamic value evaluation:
257
+
258
+ **`{{ }} - Standard Expression Evaluation**
259
+ - Used for boolean conditions and value comparisons
260
+ - Syntax: `{{ expression }}`
261
+ - Example: `{{ $value === 'pending' }}`, `{{ $host.isLoggedIn }}`
262
+ - Context variables: `$value`, `$item`, `$index`, `$host`, `$parentHost`, `$appHost`, etc.
263
+
264
+ **`{{= }} - Function Call & Return Expression**
265
+ - Evaluates JavaScript expressions and returns result
266
+ - Syntax: `{{= functionCall() }}` or `{{= computedValue }}`
267
+ - Automatically executes functions and captures return values
268
+ - Example: `{{= $item.name }}`, `{{= $parentHost.getData() }}`, `{{= formatDate($item.date) }}`
269
+ - Used in attributes for dynamic substitution
270
+ - Result is converted to string for DOM attributes
271
+
272
+ **Context Variables Available in All Directives:**
273
+ - `$value` - the value passed to the template
274
+ - `$host` - the current Web Component instance
275
+ - `$parentHost` - parent component
276
+ - `$appHost` - root application component
277
+ - `$item` - current item (in SwcLoop)
278
+ - `$index` - current index (in SwcLoop)
279
+ - Helper functions - utility methods from `SwcUtils.getHelperAndHostSet()`
280
+
281
+ ---
282
+
254
283
  #### 8.1 **SwcChoose - Multi-Condition Rendering**
255
284
 
256
285
  Switch-case style conditional rendering with `swc-when` and `swc-otherwise` sub-templates.
@@ -271,17 +300,17 @@ class StatusDisplay extends HTMLElement {
271
300
  render() {
272
301
  return `
273
302
  <template id="status-template" is="swc-choose">
274
- <!-- Pending State -->
303
+ <!-- Pending State: Using {{ }} for condition -->
275
304
  <template is="swc-when" value="{{ $value === 'pending' }}">
276
305
  <div style="color: orange;">⏳ Processing...</div>
277
306
  </template>
278
307
 
279
- <!-- Success State -->
308
+ <!-- Success State: Using {{ }} for condition -->
280
309
  <template is="swc-when" value="{{ $value === 'success' }}">
281
310
  <div style="color: green;">✓ Completed</div>
282
311
  </template>
283
312
 
284
- <!-- Error State -->
313
+ <!-- Error State: Using {{ }} for condition -->
285
314
  <template is="swc-when" value="{{ $value === 'error' }}">
286
315
  <div style="color: red;">✗ Failed</div>
287
316
  </template>
@@ -296,11 +325,31 @@ class StatusDisplay extends HTMLElement {
296
325
  }
297
326
  ```
298
327
 
299
- **Features:**
328
+ **Expression Features:**
300
329
  - `{{ }} braces` for dynamic condition evaluation
301
330
  - `$value` contains the value passed to `swc-choose`
302
331
  - `skip-if-same` attribute prevents re-render when same template selected
303
- - Attribute substitution: `attribute-name="{{ expression }}"` automatically evaluated
332
+ - **Attribute substitution with `{{= }}`**: `attribute-name="{{= expression }}"` automatically evaluated
333
+
334
+ **Attribute Substitution Example ({{= }} usage):**
335
+ ```html
336
+ <template is="swc-choose">
337
+ <template is="swc-when" value="{{ $value?.type === 'user' }}">
338
+ <user-card
339
+ data-username="{{= $value?.name }}"
340
+ data-email="{{= $value?.email }}"
341
+ data-id="{{= $value?.id }}"
342
+ ></user-card>
343
+ </template>
344
+
345
+ <template is="swc-when" value="{{ $value?.type === 'product' }}">
346
+ <product-card
347
+ data-product-name="{{= $value?.title }}"
348
+ data-price="{{= $value?.price }}"
349
+ ></product-card>
350
+ </template>
351
+ </template>
352
+ ```
304
353
 
305
354
  ---
306
355
 
@@ -312,6 +361,7 @@ If-then-else rendering with optional `swc-default` fallback.
312
361
  @elementDefine('user-profile')
313
362
  class UserProfile extends HTMLElement {
314
363
  private isLoggedIn = false;
364
+ private userData = { userName: 'Alice', userId: 123 };
315
365
 
316
366
  @setProperty('#content', 'value')
317
367
  checkAuth() {
@@ -321,10 +371,15 @@ class UserProfile extends HTMLElement {
321
371
  @onConnectedInnerHtml
322
372
  render() {
323
373
  return `
324
- <!-- True condition: renders main template -->
374
+ <!-- True condition: renders main template using {{ }} -->
325
375
  <template id="content" is="swc-if" value="{{ $host.isLoggedIn }}">
376
+ <!-- Attribute substitution with {{= }} expressions -->
377
+ <user-card
378
+ data-username="{{= $host.userData.userName }}"
379
+ data-userid="{{= $host.userData.userId }}"
380
+ ></user-card>
326
381
  <div>
327
- <h2>Welcome, {{ $host.userName }}</h2>
382
+ <h2>Welcome, {{ $host.userData.userName }}</h2>
328
383
  <button on-click="logout">Logout</button>
329
384
  </div>
330
385
 
@@ -341,12 +396,13 @@ class UserProfile extends HTMLElement {
341
396
  }
342
397
  ```
343
398
 
344
- **Features:**
345
- - Binary true/false logic
399
+ **Expression Features:**
400
+ - Binary true/false logic with `{{ }} condition`
346
401
  - Main template renders when `value` is truthy
347
402
  - `swc-default` sub-template renders when value is falsy
348
- - Dynamic attribute substitution supported
403
+ - Dynamic attribute substitution with `{{= }}` supported
349
404
  - Access `$host`, `$value`, and other context variables
405
+ - `{{= functionCall() }}` executes functions and returns results for attributes
350
406
 
351
407
  ---
352
408
 
@@ -362,7 +418,7 @@ class DataLoader extends HTMLElement {
362
418
  async fetchData() {
363
419
  return new Promise((resolve, reject) => {
364
420
  setTimeout(() => {
365
- resolve({ id: 1, name: 'Sample Data' });
421
+ resolve({ id: 1, name: 'Sample Data', description: 'API response' });
366
422
  }, 2000);
367
423
  });
368
424
  }
@@ -375,17 +431,23 @@ class DataLoader extends HTMLElement {
375
431
  @onConnectedInnerHtml
376
432
  render() {
377
433
  return `
378
- <template id="async-content" is="swc-async" value="{{ $host.fetchData() }}">
434
+ <template id="async-content" is="swc-async" value="{{= $host.fetchData() }}">
379
435
  <!-- Loading State: Shows while Promise is pending -->
380
436
  <template is="swc-loading">
381
437
  <div>🔄 Loading data...</div>
382
438
  </template>
383
439
 
384
440
  <!-- Success State: Shows when Promise resolves -->
441
+ <!-- Using {{= }} to extract data from resolved Promise -->
385
442
  <template is="swc-success">
443
+ <data-card
444
+ data-id="{{= $value.id }}"
445
+ data-name="{{= $value.name }}"
446
+ ></data-card>
386
447
  <div>
387
448
  <p>Data ID: {{ $value.id }}</p>
388
449
  <p>Data Name: {{ $value.name }}</p>
450
+ <p>Description: {{= $value.description }}</p>
389
451
  </div>
390
452
  </template>
391
453
 
@@ -399,12 +461,14 @@ class DataLoader extends HTMLElement {
399
461
  }
400
462
  ```
401
463
 
402
- **Features:**
403
- - Automatically manages Promise lifecycle
464
+ **Expression Features:**
465
+ - Promise lifecycle management with `{{ }} conditions`
466
+ - `{{= $host.fetchData() }}` - function call expression that executes and returns Promise
467
+ - `{{= $value.propertyName }}` - extract properties from resolved value
404
468
  - `swc-loading` - displays during pending state
405
- - `swc-success` - displays on successful resolution, `$value` contains result
406
- - `swc-error` - displays on Promise rejection
407
- - Dynamic attribute substitution in all states
469
+ - `swc-success` - displays on successful resolution, `$value` contains resolved result
470
+ - `swc-error` - displays on Promise rejection, `$value` contains error
471
+ - Dynamic attribute substitution with `{{= }}` in all states
408
472
  - `on-clone-node` and `on-clone-nodes` callbacks for DOM manipulation
409
473
 
410
474
  ---
@@ -417,9 +481,9 @@ Iterate over arrays and render templates for each item.
417
481
  @elementDefine('product-list')
418
482
  class ProductList extends HTMLElement {
419
483
  private products = [
420
- { id: 1, name: 'Laptop', price: 1200 },
421
- { id: 2, name: 'Phone', price: 800 },
422
- { id: 3, name: 'Tablet', price: 500 }
484
+ { id: 1, name: 'Laptop', price: 1200, category: 'electronics' },
485
+ { id: 2, name: 'Phone', price: 800, category: 'electronics' },
486
+ { id: 3, name: 'Tablet', price: 500, category: 'electronics' }
423
487
  ];
424
488
 
425
489
  @setProperty('#products-list', 'value')
@@ -430,12 +494,26 @@ class ProductList extends HTMLElement {
430
494
  @onConnectedInnerHtml
431
495
  render() {
432
496
  return `
433
- <template id="products-list" is="swc-loop" value="{{ $host.products }}">
497
+ <template id="products-list" is="swc-loop" value="{{= $host.products }}">
498
+ <!-- Loop iteration with {{ }} for display and {{= }} for attributes -->
434
499
  <div style="margin: 10px; padding: 10px; border: 1px solid #ddd;">
500
+ <!-- Using {{ }} for template content rendering -->
435
501
  <h3>{{ $item.name }}</h3>
436
502
  <p>Price: ${{ $item.price }}</p>
437
503
  <p>ID: {{ $item.id }} (Index: {{ $index }})</p>
438
- <button data-id="{{ $item.id }}">Add to Cart</button>
504
+
505
+ <!-- Using {{= }} for dynamic attribute substitution -->
506
+ <product-card
507
+ data-product-id="{{= $item.id }}"
508
+ data-product-name="{{= $item.name }}"
509
+ data-product-price="{{= $item.price }}"
510
+ data-product-category="{{= $item.category }}"
511
+ ></product-card>
512
+
513
+ <!-- Computed expressions with {{= }} -->
514
+ <button data-id="{{= $item.id }}" data-price="{{= $item.price }}">
515
+ Add to Cart - \${{= $item.price }}
516
+ </button>
439
517
  </div>
440
518
 
441
519
  <!-- Empty fallback: renders when array is empty -->
@@ -448,26 +526,76 @@ class ProductList extends HTMLElement {
448
526
  }
449
527
  ```
450
528
 
451
- **Context variables:**
529
+ **Context Variables (Available in loop):**
452
530
  - `$item` - current item in iteration
453
- - `$index` - zero-based index
454
- - `$value` - entire array
531
+ - `$index` - zero-based index (0, 1, 2, ...)
532
+ - `$value` - entire array being iterated
455
533
  - `$nodes` - cloned DOM nodes
456
534
  - `$elements` - cloned HTML elements
457
535
  - `$firstElement` - first element in cloned nodes
458
536
 
459
- **Features:**
460
- - Efficient DOM cloning for each item
537
+ **Expression Features:**
538
+ - `{{= $host.products }}` - function call expression that returns the array to iterate
539
+ - `{{ $item.propertyName }}` - display item properties using standard `{{ }}`
540
+ - `{{= $item.propertyName }}` - extract item properties for attributes using `{{= }}`
541
+ - `{{= computedValue }}` - compute values in attributes (e.g., calculations, method calls)
461
542
  - `swc-default` fallback renders when array is empty
462
- - All cloned attributes support `{{ }}` substitution
543
+ - All cloned attributes support `{{ }}` and `{{= }}` substitution
463
544
  - `on-clone-node` callback fires for each cloned node
464
545
  - `on-clone-nodes` callback fires after all nodes cloned
465
546
 
547
+ **Common Patterns:**
548
+ ```html
549
+ <!-- Template functions with {{= }} -->
550
+ <template is="swc-loop" value="{{= filterProducts($host.products) }}">
551
+ <!-- Dynamic calculations -->
552
+ <span>Total: {{= $item.price * $item.quantity }}</span>
553
+
554
+ <!-- Conditional attributes -->
555
+ <div class="{{= $item.inStock ? 'available' : 'unavailable' }}"></div>
556
+
557
+ <!-- Method calls as attributes -->
558
+ <button data-formatted="{{= formatPrice($item.price) }}">
559
+ Buy - {{ formatPrice($item.price) }}
560
+ </button>
561
+ </template>
562
+ ```
563
+
564
+ **Advanced: replace-wrap for Custom Expression Syntax**
565
+
566
+ Override default `{{ }}` and `{{= }}` syntax with custom wrappers:
567
+
568
+ ```typescript
569
+ @elementDefine('custom-loop')
570
+ class CustomLoop extends HTMLElement {
571
+ private items = [{ id: 1, name: 'Item 1' }];
572
+
573
+ @onConnectedInnerHtml
574
+ render() {
575
+ return `
576
+ <!-- Using custom wrapper syntax [(= ... )] instead of {{= ... }} -->
577
+ <template id="items" is="swc-loop" replace-wrap="[(= )]" value="[(= $host.items )]">
578
+ <div>
579
+ <p>Name: [(= $item.name )]</p>
580
+ <button data-id="[(= $item.id )]">Click me</button>
581
+ </div>
582
+ </template>
583
+ `;
584
+ }
585
+ }
586
+ ```
587
+
588
+ **replace-wrap attribute options:**
589
+ - Change expression wrapper from default `{{= }}` to custom pattern
590
+ - Useful when `{{ }}` conflicts with template engines like EJS or Mustache
591
+ - Supported on: `SwcLoop`, `SwcChoose`, `SwcIf`, `SwcAsync`, `register()` directives
592
+ - Example patterns: `[(= )]`, `{[= ]}`, `<%= %>` (after escaping)
593
+
466
594
  ---
467
595
 
468
596
  #### 8.5 **Declarative Routing with swc-choose**
469
597
 
470
- Combine `@subscribeSwcAppRouteChange` with `swc-choose` for clean, declarative routing without boilerplate.
598
+ Combine `@subscribeSwcAppRouteChangeWhileConnected` with `swc-choose` for clean, declarative routing without boilerplate.
471
599
 
472
600
  ```typescript
473
601
  @elementDefine('root-router')
@@ -480,23 +608,37 @@ class RootRouter extends HTMLElement {
480
608
  }
481
609
 
482
610
  @setProperty('#router', 'value')
483
- @subscribeSwcAppRouteChange(['/', '/product/{id}'])
484
- routeChanged(router: RouterEventType) {
485
- return router;
611
+ @subscribeSwcAppRouteChangeWhileConnected(['/', '/users', '/users/{id}', '/products/{id}'])
612
+ routeChanged(route: RouterEventType) {
613
+ return route;
614
+ }
615
+
616
+ navigate(path: string): void {
617
+ this.router?.go(path);
486
618
  }
487
619
 
488
620
  @onConnectedInnerHtml
489
621
  render() {
490
622
  return `
491
623
  <template id="router" is="swc-choose">
492
- <!-- Home -->
624
+ <!-- Home Page: Using {{ }} for condition -->
493
625
  <template is="swc-when" value="{{ ['', '/'].includes($value?.path) }}">
494
626
  <home-page/>
495
627
  </template>
496
628
 
497
- <!-- Product Detail -->
498
- <template is="swc-when" value="{{ $value?.path.startsWith('/product/') }}">
499
- <product-page product-id="{{$value?.pathData?.id}}"/>
629
+ <!-- Users List Page -->
630
+ <template is="swc-when" value="{{ $value?.path === '/users' }}">
631
+ <users-list-page/>
632
+ </template>
633
+
634
+ <!-- User Detail Page: Using {{= }} for dynamic attributes from route params -->
635
+ <template is="swc-when" value="{{ $value?.path.startsWith('/users/') }}">
636
+ <user-detail-page user-id="{{= $value?.pathData?.id }}"></user-detail-page>
637
+ </template>
638
+
639
+ <!-- Product Detail Page: Using {{= }} for dynamic route parameters -->
640
+ <template is="swc-when" value="{{ $value?.path.startsWith('/products/') }}">
641
+ <product-detail-page product-id="{{= $value?.pathData?.id }}"></product-detail-page>
500
642
  </template>
501
643
 
502
644
  <!-- Not Found -->
@@ -511,12 +653,107 @@ class RootRouter extends HTMLElement {
511
653
 
512
654
  **Benefits:**
513
655
  - ✅ **No imperative route methods** - routes are declarative templates
514
- - ✅ **Automatic re-rendering** - attributes like `product-id` update automatically
656
+ - ✅ **Automatic re-rendering** - attributes like `user-id` update automatically
515
657
  - ✅ **Performance optimization** - use `skip-if-same` on templates to prevent re-renders
516
- - ✅ **Dynamic path parameters** - use `{{$value?.pathData?.id}}` syntax to inject route params
658
+ - ✅ **Dynamic path parameters** - use `{{= $value?.pathData?.id }}` syntax to inject route params with `{{= }}`
517
659
  - ✅ **Cleaner DX** - single unified routing pattern
660
+ - ✅ **Full expression support** - use `{{= }}` for complex parameter transformations
661
+
662
+ ### 9. **Component Communication - Message Bus**
663
+
664
+ SWC provides a powerful message bus system for inter-component communication through SwcApp. Components can publish and subscribe to typed messages while connected.
665
+
666
+ #### @subscribeSwcAppMessageWhileConnected
667
+ Subscribe to messages while component is connected to DOM.
668
+
669
+ ```typescript
670
+ @elementDefine('notification-panel')
671
+ class NotificationPanel extends HTMLElement {
672
+ @subscribeSwcAppMessageWhileConnected()
673
+ onAnyMessage(message: SwcAppMessage) {
674
+ console.log('Received message:', message);
675
+ }
676
+
677
+ @subscribeSwcAppMessageWhileConnected('user-login')
678
+ onUserLogin(message: SwcAppMessage<{ username: string }>) {
679
+ console.log(`Welcome ${message.data?.username}`);
680
+ }
681
+
682
+ @subscribeSwcAppMessageWhileConnected('user-login', {
683
+ filter: (msg) => msg.data?.username === 'admin'
684
+ })
685
+ onAdminLogin(message: SwcAppMessage) {
686
+ console.log('Admin logged in!');
687
+ }
688
+ }
689
+ ```
690
+
691
+ #### @publishSwcAppMessage
692
+ Publish a message from a method's return value.
693
+
694
+ ```typescript
695
+ @elementDefine('login-form')
696
+ class LoginForm extends HTMLElement {
697
+ @publishSwcAppMessage()
698
+ async onSubmit() {
699
+ const user = await this.authService.login(
700
+ this.username,
701
+ this.password
702
+ );
703
+ return user; // Published as message with data: user
704
+ }
705
+
706
+ @publishSwcAppMessage('user-profile-updated')
707
+ updateProfile() {
708
+ const profile = { name: this.name, email: this.email };
709
+ return profile; // Published as message with type: 'user-profile-updated'
710
+ }
711
+ }
712
+ ```
713
+
714
+ **SwcAppMessage Structure:**
715
+ ```typescript
716
+ type SwcAppMessage<T = any> = {
717
+ publisher?: any; // Component that published the message
718
+ data?: T; // Payload data
719
+ type?: string; // Optional message type/category
720
+ };
721
+ ```
722
+
723
+ **Key Features:**
724
+ - ✅ **Lifecycle-aware** - subscriptions only active while component is connected
725
+ - ✅ **Type-safe** - specify message types for filtering
726
+ - ✅ **Filter support** - use custom filter functions to handle specific conditions
727
+ - ✅ **Auto-publishing** - return value automatically becomes message payload
728
+ - ✅ **Async support** - works with async methods (promises)
729
+ - ✅ **Centralized** - all messages routed through SwcApp host
730
+ - ✅ **Decoupled** - components don't need to know about each other
731
+
732
+ **Usage Example:**
733
+ ```typescript
734
+ // Publisher component
735
+ @elementDefine('product-list')
736
+ class ProductList extends HTMLElement {
737
+ @publishSwcAppMessage('product-selected')
738
+ selectProduct(productId: string) {
739
+ const product = this.findProduct(productId);
740
+ return product;
741
+ }
742
+ }
743
+
744
+ // Subscriber component
745
+ @elementDefine('product-detail')
746
+ class ProductDetail extends HTMLElement {
747
+ @subscribeSwcAppMessageWhileConnected('product-selected')
748
+ onProductSelected(message: SwcAppMessage<Product>) {
749
+ this.displayProduct(message.data);
750
+ }
751
+ }
752
+ ```
753
+
754
+ ---
518
755
 
519
- ### 9. **Accommodation Pattern**
756
+ ### 10. **Accommodation Pattern**
520
757
  Factory-based component registration with explicit DI.
521
758
 
522
759
  ```typescript
@@ -555,7 +792,7 @@ appElement.connect({
555
792
  });
556
793
  ```
557
794
 
558
- ### 10. **Quickstart - Basic SPA Setup**
795
+ ### 11. **Quickstart - Basic SPA Setup**
559
796
 
560
797
  Complete example of setting up a production SPA with routing, services, and components.
561
798
 
@@ -631,7 +868,7 @@ export const serviceFactories = [userServiceFactory];
631
868
  #### Step 3. Router Configuration (Declarative with swc-choose)
632
869
  ```typescript
633
870
  // pages/RootRouter.ts
634
- import { elementDefine, subscribeSwcAppRouteChange, setProperty, onConnectedInnerHtml, onInitialize } from '@dooboostore/simple-web-component';
871
+ import { elementDefine, subscribeSwcAppRouteChangeWhileConnected, setProperty, onConnectedInnerHtml, onInitialize } from '@dooboostore/simple-web-component';
635
872
  import { Router, RouterEventType } from '@dooboostore/core-web';
636
873
 
637
874
  const rootRouterFactory = (w: Window) => {
@@ -649,7 +886,7 @@ const rootRouterFactory = (w: Window) => {
649
886
  }
650
887
 
651
888
  @setProperty('#router', 'value')
652
- @subscribeSwcAppRouteChange(['/', '/users', '/users/{id}'])
889
+ @subscribeSwcAppRouteChangeWhileConnected(['/', '/users', '/users/{id}'])
653
890
  routeChanged(route: RouterEventType) {
654
891
  return route;
655
892
  }
@@ -933,7 +1170,7 @@ src/
933
1170
  3. `bootFactory` registers services and components (including `rootRouterFactory`)
934
1171
  4. App waits for `swc-app-body` to be defined
935
1172
  5. `appElement.connect()` initializes routing & DI
936
- 6. `<root-router>` becomes active with `@subscribeSwcAppRouteChange` + `swc-choose` template
1173
+ 6. `<root-router>` becomes active with `@subscribeSwcAppRouteChangeWhileConnected` + `swc-choose` template
937
1174
  7. Route changes automatically trigger `swc-choose` re-evaluation and template re-rendering
938
1175
  8. Template attributes like `user-id="{{$value?.pathData?.id}}"` are dynamically populated with route params
939
1176
  9. All components have access to injected services via `@onInitialize` or `@onConnectedSwcApp`
@@ -50,7 +50,7 @@ function createStyleDecorator(action) {
50
50
  if (res !== void 0) {
51
51
  const win = this.ownerDocument?.defaultView || window;
52
52
  const host = this;
53
- const hostSet = { ...import_Utils.SwcUtils.getHelperAndHostSet(win, host), $this: this };
53
+ const hostSet = import_Utils.SwcUtils.getHelperAndHostSet(win, host);
54
54
  const r = options.root || "auto";
55
55
  const targetEls = [];
56
56
  const applyRoot = (t) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/decorators/applyStyle.ts"],
4
- "sourcesContent": ["import { ReflectUtils } from '@dooboostore/core';\nimport { ensureInit } from './elementDefine';\nimport { SwcUtils } from '../utils/Utils';\nimport { SwcQueryOptions, HelperHostSet } from '../types';\n\nexport type StyleAction = 'set' | 'update' | 'remove';\n\nexport interface StyleApplyOptions extends SwcQueryOptions {}\n\nexport interface StyleApplyMetadata {\n propertyKey: string | symbol;\n selector: string;\n action: StyleAction;\n options: StyleApplyOptions;\n}\n\nexport const STYLE_METADATA_KEY = Symbol.for('simple-web-component:style');\n\nfunction createStyleDecorator(action: StyleAction) {\n return (selector: string, options: StyleApplyOptions = {}): MethodDecorator => {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n let metaList = ReflectUtils.getOwnMetadata(STYLE_METADATA_KEY, constructor) as Map<string | symbol, StyleApplyMetadata>;\n if (!metaList) {\n metaList = new Map<string | symbol, StyleApplyMetadata>();\n ReflectUtils.defineMetadata(STYLE_METADATA_KEY, metaList, constructor);\n }\n metaList.set(propertyKey, { propertyKey, selector, action, options });\n\n const original = descriptor.value;\n descriptor.value = async function (...args: any[]) {\n ensureInit(this);\n const res = await (original as any).apply(this, args);\n if (res !== undefined) {\n const win = (this as any).ownerDocument?.defaultView || window;\n const host = this as unknown as HTMLElement;\n const hostSet = { ...SwcUtils.getHelperAndHostSet(win, host), $this: this };\n const r = options.root || 'auto';\n const targetEls: HTMLElement[] = [];\n\n const applyRoot = (t: any) => {\n if (!t || !(t instanceof win.HTMLElement)) return;\n targetEls.push(t);\n };\n\n if (selector === ':parentHost') applyRoot(hostSet.$parentHost);\n else if (selector === ':appHost') applyRoot(hostSet.$appHost);\n else if (selector === ':firstHost') applyRoot(hostSet.$firstHost);\n else if (selector === ':lastHost') applyRoot(hostSet.$lastHost);\n else if (selector === ':firstAppHost') applyRoot(hostSet.$firstAppHost);\n else if (selector === ':lastAppHost') applyRoot(hostSet.$lastAppHost);\n else if (selector === ':hosts') hostSet.$hosts.forEach(applyRoot);\n else if (selector === ':appHosts') hostSet.$appHosts.forEach(applyRoot);\n else if (selector === ':host' || !selector) applyRoot(host);\n else {\n const targetRoot = r === 'auto' ? (host.shadowRoot || host) : (r === 'shadow' ? host.shadowRoot : host);\n if (targetRoot) {\n const found = targetRoot.querySelectorAll(selector);\n if (found) targetEls.push(...(Array.from(found) as HTMLElement[]));\n }\n }\n\n targetEls.forEach(targetEl => {\n const resolvedRes = typeof res === 'function' ? (res as any)(targetEl, hostSet) : res;\n\n if (action === 'set' || action === 'update') {\n if (action === 'set') targetEl.style.cssText = '';\n \n if (typeof resolvedRes === 'object' && resolvedRes !== null && !Array.isArray(resolvedRes)) {\n Object.entries(resolvedRes as any).forEach(([prop, val]) => {\n const finalVal = typeof val === 'function' ? val(targetEl, hostSet) : val;\n if (finalVal === null || finalVal === undefined) {\n targetEl.style.removeProperty(prop);\n } else {\n targetEl.style[prop as any] = String(finalVal);\n }\n });\n } else if (typeof resolvedRes === 'string') {\n targetEl.style.cssText = resolvedRes;\n }\n } else if (action === 'remove') {\n if (typeof resolvedRes === 'object' && resolvedRes !== null && !Array.isArray(resolvedRes)) {\n Object.entries(resolvedRes as any).forEach(([prop, val]) => {\n const shouldRemove = typeof val === 'function' ? val(targetEl, hostSet) : !!val;\n if (shouldRemove) {\n targetEl.style.removeProperty(prop);\n }\n });\n } else {\n const props = Array.isArray(resolvedRes) ? resolvedRes : [resolvedRes];\n props.forEach(p => targetEl.style.removeProperty(String(p)));\n }\n }\n });\n }\n return res;\n };\n return descriptor;\n };\n };\n}\n\nexport function applyStyle(selector: string, action: StyleAction = 'update', options: StyleApplyOptions = {}): MethodDecorator {\n return createStyleDecorator(action)(selector, options);\n}\n\nexport const setStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('set')(selector, options);\nexport const updateStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('update')(selector, options);\nexport const removeStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('remove')(selector, options);\n\n// Host versions\nexport function applyStyleHost(action: StyleAction = 'update', options: StyleApplyOptions = {}): MethodDecorator {\n return createStyleDecorator(action)(':host', options);\n}\nexport const setStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('set')(':host', options);\nexport const updateStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('update')(':host', options);\nexport const removeStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('remove')(':host', options);\n\nexport const findAllStyleMetadata = (target: any): Map<string | symbol, StyleApplyMetadata> => {\n const result = new Map<string | symbol, StyleApplyMetadata>();\n const maps = ReflectUtils.findAllMetadata<Map<string | symbol, StyleApplyMetadata>>(STYLE_METADATA_KEY, target);\n maps.forEach(map => {\n if (map instanceof Map) {\n map.forEach((v, k) => result.set(k, v));\n }\n });\n return result;\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { ReflectUtils } from '@dooboostore/core';\nimport { ensureInit } from './elementDefine';\nimport { SwcUtils } from '../utils/Utils';\nimport { SwcQueryOptions, HelperHostSet } from '../types';\n\nexport type StyleAction = 'set' | 'update' | 'remove';\n\nexport interface StyleApplyOptions extends SwcQueryOptions {}\n\nexport interface StyleApplyMetadata {\n propertyKey: string | symbol;\n selector: string;\n action: StyleAction;\n options: StyleApplyOptions;\n}\n\nexport const STYLE_METADATA_KEY = Symbol.for('simple-web-component:style');\n\nfunction createStyleDecorator(action: StyleAction) {\n return (selector: string, options: StyleApplyOptions = {}): MethodDecorator => {\n return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {\n const constructor = target.constructor;\n let metaList = ReflectUtils.getOwnMetadata(STYLE_METADATA_KEY, constructor) as Map<string | symbol, StyleApplyMetadata>;\n if (!metaList) {\n metaList = new Map<string | symbol, StyleApplyMetadata>();\n ReflectUtils.defineMetadata(STYLE_METADATA_KEY, metaList, constructor);\n }\n metaList.set(propertyKey, { propertyKey, selector, action, options });\n\n const original = descriptor.value;\n descriptor.value = async function (...args: any[]) {\n ensureInit(this);\n const res = await (original as any).apply(this, args);\n if (res !== undefined) {\n const win = (this as any).ownerDocument?.defaultView || window;\n const host = this as unknown as HTMLElement;\n const hostSet = SwcUtils.getHelperAndHostSet(win, host);\n const r = options.root || 'auto';\n const targetEls: HTMLElement[] = [];\n\n const applyRoot = (t: any) => {\n if (!t || !(t instanceof win.HTMLElement)) return;\n targetEls.push(t);\n };\n\n if (selector === ':parentHost') applyRoot(hostSet.$parentHost);\n else if (selector === ':appHost') applyRoot(hostSet.$appHost);\n else if (selector === ':firstHost') applyRoot(hostSet.$firstHost);\n else if (selector === ':lastHost') applyRoot(hostSet.$lastHost);\n else if (selector === ':firstAppHost') applyRoot(hostSet.$firstAppHost);\n else if (selector === ':lastAppHost') applyRoot(hostSet.$lastAppHost);\n else if (selector === ':hosts') hostSet.$hosts.forEach(applyRoot);\n else if (selector === ':appHosts') hostSet.$appHosts.forEach(applyRoot);\n else if (selector === ':host' || !selector) applyRoot(host);\n else {\n const targetRoot = r === 'auto' ? (host.shadowRoot || host) : (r === 'shadow' ? host.shadowRoot : host);\n if (targetRoot) {\n const found = targetRoot.querySelectorAll(selector);\n if (found) targetEls.push(...(Array.from(found) as HTMLElement[]));\n }\n }\n\n targetEls.forEach(targetEl => {\n const resolvedRes = typeof res === 'function' ? (res as any)(targetEl, hostSet) : res;\n\n if (action === 'set' || action === 'update') {\n if (action === 'set') targetEl.style.cssText = '';\n \n if (typeof resolvedRes === 'object' && resolvedRes !== null && !Array.isArray(resolvedRes)) {\n Object.entries(resolvedRes as any).forEach(([prop, val]) => {\n const finalVal = typeof val === 'function' ? val(targetEl, hostSet) : val;\n if (finalVal === null || finalVal === undefined) {\n targetEl.style.removeProperty(prop);\n } else {\n targetEl.style[prop as any] = String(finalVal);\n }\n });\n } else if (typeof resolvedRes === 'string') {\n targetEl.style.cssText = resolvedRes;\n }\n } else if (action === 'remove') {\n if (typeof resolvedRes === 'object' && resolvedRes !== null && !Array.isArray(resolvedRes)) {\n Object.entries(resolvedRes as any).forEach(([prop, val]) => {\n const shouldRemove = typeof val === 'function' ? val(targetEl, hostSet) : !!val;\n if (shouldRemove) {\n targetEl.style.removeProperty(prop);\n }\n });\n } else {\n const props = Array.isArray(resolvedRes) ? resolvedRes : [resolvedRes];\n props.forEach(p => targetEl.style.removeProperty(String(p)));\n }\n }\n });\n }\n return res;\n };\n return descriptor;\n };\n };\n}\n\nexport function applyStyle(selector: string, action: StyleAction = 'update', options: StyleApplyOptions = {}): MethodDecorator {\n return createStyleDecorator(action)(selector, options);\n}\n\nexport const setStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('set')(selector, options);\nexport const updateStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('update')(selector, options);\nexport const removeStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('remove')(selector, options);\n\n// Host versions\nexport function applyStyleHost(action: StyleAction = 'update', options: StyleApplyOptions = {}): MethodDecorator {\n return createStyleDecorator(action)(':host', options);\n}\nexport const setStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('set')(':host', options);\nexport const updateStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('update')(':host', options);\nexport const removeStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('remove')(':host', options);\n\nexport const findAllStyleMetadata = (target: any): Map<string | symbol, StyleApplyMetadata> => {\n const result = new Map<string | symbol, StyleApplyMetadata>();\n const maps = ReflectUtils.findAllMetadata<Map<string | symbol, StyleApplyMetadata>>(STYLE_METADATA_KEY, target);\n maps.forEach(map => {\n if (map instanceof Map) {\n map.forEach((v, k) => result.set(k, v));\n }\n });\n return result;\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -27,6 +27,7 @@ module.exports = __toCommonJS(attribute_exports);
27
27
  var import_core = require("@dooboostore/core");
28
28
  var import_elementDefine = require("./elementDefine");
29
29
  var import_Utils = require("../utils/Utils");
30
+ var import_core_web = require("@dooboostore/core-web");
30
31
  const ATTRIBUTE_FIELD_METADATA_KEY = Symbol.for("simple-web-component:attribute-field");
31
32
  const convertValue = (val, type) => {
32
33
  if (val === null || val === void 0) return val;
@@ -115,7 +116,22 @@ function attribute(selector, options = {}) {
115
116
  const primaryTarget = targets[0];
116
117
  if (primaryTarget && typeof primaryTarget.hasAttribute === "function") {
117
118
  if (primaryTarget.hasAttribute(attrName)) {
118
- const domVal = primaryTarget.getAttribute(attrName);
119
+ let domVal = primaryTarget.getAttribute(attrName);
120
+ const ae = new import_core.ActionExpression(domVal);
121
+ const expr = ae.getFirstExpression("call-return");
122
+ if (expr) {
123
+ try {
124
+ const result = import_core.FunctionUtils.executeReturn({
125
+ script: import_core_web.ConvertUtils.decodeHtmlEntity(expr.script, currentWin.document),
126
+ context: this,
127
+ args: import_Utils.SwcUtils.getHelperAndHostSet(currentWin, this)
128
+ });
129
+ return convertValue(result, targetType);
130
+ } catch (e) {
131
+ console.error(`[SWC] Failed to execute directive {{= ${expr.script} }}:`, e);
132
+ return convertValue(domVal, targetType);
133
+ }
134
+ }
119
135
  return convertValue(domVal, targetType);
120
136
  }
121
137
  return null;