@dooboostore/simple-web-component 1.0.54 → 1.0.56

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 (124) hide show
  1. package/README.md +342 -56
  2. package/dist/cjs/decorators/addEventListener.js +37 -14
  3. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  4. package/dist/cjs/decorators/applyAttribute.js +6 -3
  5. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  6. package/dist/cjs/decorators/applyClass.js +18 -2
  7. package/dist/cjs/decorators/applyClass.js.map +2 -2
  8. package/dist/cjs/decorators/applyNode.js +10 -3
  9. package/dist/cjs/decorators/applyNode.js.map +2 -2
  10. package/dist/cjs/decorators/changedAttribute.js +2 -5
  11. package/dist/cjs/decorators/changedAttribute.js.map +2 -2
  12. package/dist/cjs/decorators/elementDefine.js +13 -2
  13. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  14. package/dist/cjs/decorators/eventMedia.js +2 -5
  15. package/dist/cjs/decorators/eventMedia.js.map +2 -2
  16. package/dist/cjs/decorators/fetch.js +216 -82
  17. package/dist/cjs/decorators/fetch.js.map +3 -3
  18. package/dist/cjs/decorators/index.js +1 -0
  19. package/dist/cjs/decorators/index.js.map +2 -2
  20. package/dist/cjs/decorators/intersectionObserver.js +3 -6
  21. package/dist/cjs/decorators/intersectionObserver.js.map +2 -2
  22. package/dist/cjs/decorators/mutationObserver.js +3 -6
  23. package/dist/cjs/decorators/mutationObserver.js.map +2 -2
  24. package/dist/cjs/decorators/parameter.js +197 -33
  25. package/dist/cjs/decorators/parameter.js.map +3 -3
  26. package/dist/cjs/decorators/persistState.js +474 -0
  27. package/dist/cjs/decorators/persistState.js.map +7 -0
  28. package/dist/cjs/decorators/resizeObserver.js +3 -6
  29. package/dist/cjs/decorators/resizeObserver.js.map +2 -2
  30. package/dist/cjs/decorators/setInterval.js +2 -5
  31. package/dist/cjs/decorators/setInterval.js.map +2 -2
  32. package/dist/cjs/decorators/setTimeout.js +2 -5
  33. package/dist/cjs/decorators/setTimeout.js.map +2 -2
  34. package/dist/cjs/decorators/subscribeSwcAppMessage.js.map +1 -1
  35. package/dist/cjs/elements/SwcAppMixin.js +50 -2
  36. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  37. package/dist/esm/decorators/addEventListener.js +38 -15
  38. package/dist/esm/decorators/addEventListener.js.map +2 -2
  39. package/dist/esm/decorators/applyAttribute.js +6 -3
  40. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  41. package/dist/esm/decorators/applyClass.js +18 -2
  42. package/dist/esm/decorators/applyClass.js.map +2 -2
  43. package/dist/esm/decorators/applyNode.js +10 -3
  44. package/dist/esm/decorators/applyNode.js.map +2 -2
  45. package/dist/esm/decorators/changedAttribute.js +3 -6
  46. package/dist/esm/decorators/changedAttribute.js.map +2 -2
  47. package/dist/esm/decorators/elementDefine.js +15 -4
  48. package/dist/esm/decorators/elementDefine.js.map +2 -2
  49. package/dist/esm/decorators/eventMedia.js +3 -6
  50. package/dist/esm/decorators/eventMedia.js.map +2 -2
  51. package/dist/esm/decorators/fetch.js +216 -82
  52. package/dist/esm/decorators/fetch.js.map +3 -3
  53. package/dist/esm/decorators/index.js +1 -0
  54. package/dist/esm/decorators/index.js.map +2 -2
  55. package/dist/esm/decorators/intersectionObserver.js +4 -7
  56. package/dist/esm/decorators/intersectionObserver.js.map +2 -2
  57. package/dist/esm/decorators/mutationObserver.js +4 -7
  58. package/dist/esm/decorators/mutationObserver.js.map +2 -2
  59. package/dist/esm/decorators/parameter.js +197 -33
  60. package/dist/esm/decorators/parameter.js.map +3 -3
  61. package/dist/esm/decorators/persistState.js +455 -0
  62. package/dist/esm/decorators/persistState.js.map +7 -0
  63. package/dist/esm/decorators/resizeObserver.js +4 -7
  64. package/dist/esm/decorators/resizeObserver.js.map +2 -2
  65. package/dist/esm/decorators/setInterval.js +3 -6
  66. package/dist/esm/decorators/setInterval.js.map +2 -2
  67. package/dist/esm/decorators/setTimeout.js +3 -6
  68. package/dist/esm/decorators/setTimeout.js.map +2 -2
  69. package/dist/esm/decorators/subscribeSwcAppMessage.js.map +1 -1
  70. package/dist/esm/elements/SwcAppMixin.js +51 -3
  71. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  72. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +4491 -3637
  73. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  74. package/dist/types/decorators/addEventListener.d.ts +15 -0
  75. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  76. package/dist/types/decorators/applyAttribute.d.ts +1 -0
  77. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  78. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  79. package/dist/types/decorators/applyNode.d.ts +4 -2
  80. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  81. package/dist/types/decorators/changedAttribute.d.ts.map +1 -1
  82. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  83. package/dist/types/decorators/eventMedia.d.ts.map +1 -1
  84. package/dist/types/decorators/fetch.d.ts +52 -31
  85. package/dist/types/decorators/fetch.d.ts.map +1 -1
  86. package/dist/types/decorators/index.d.ts +1 -0
  87. package/dist/types/decorators/index.d.ts.map +1 -1
  88. package/dist/types/decorators/intersectionObserver.d.ts.map +1 -1
  89. package/dist/types/decorators/mutationObserver.d.ts.map +1 -1
  90. package/dist/types/decorators/parameter.d.ts +169 -31
  91. package/dist/types/decorators/parameter.d.ts.map +1 -1
  92. package/dist/types/decorators/persistState.d.ts +66 -0
  93. package/dist/types/decorators/persistState.d.ts.map +1 -0
  94. package/dist/types/decorators/resizeObserver.d.ts.map +1 -1
  95. package/dist/types/decorators/setInterval.d.ts.map +1 -1
  96. package/dist/types/decorators/setTimeout.d.ts.map +1 -1
  97. package/dist/types/decorators/subscribeSwcAppMessage.d.ts +1 -1
  98. package/dist/types/decorators/subscribeSwcAppMessage.d.ts.map +1 -1
  99. package/dist/types/elements/SwcAppMixin.d.ts +12 -0
  100. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  101. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +4491 -3637
  102. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  103. package/lsp/bin/swc-lsp.js +3 -0
  104. package/lsp/out/server/server.js +9960 -0
  105. package/lsp/package.json +56 -0
  106. package/package.json +24 -9
  107. package/src/decorators/addEventListener.ts +23 -15
  108. package/src/decorators/applyAttribute.ts +8 -3
  109. package/src/decorators/applyClass.ts +22 -2
  110. package/src/decorators/applyNode.ts +18 -6
  111. package/src/decorators/changedAttribute.ts +3 -4
  112. package/src/decorators/elementDefine.ts +19 -7
  113. package/src/decorators/eventMedia.ts +3 -6
  114. package/src/decorators/fetch.ts +270 -140
  115. package/src/decorators/index.ts +1 -0
  116. package/src/decorators/intersectionObserver.ts +4 -5
  117. package/src/decorators/mutationObserver.ts +4 -5
  118. package/src/decorators/parameter.ts +326 -42
  119. package/src/decorators/persistState.ts +408 -0
  120. package/src/decorators/resizeObserver.ts +4 -5
  121. package/src/decorators/setInterval.ts +3 -4
  122. package/src/decorators/setTimeout.ts +3 -4
  123. package/src/decorators/subscribeSwcAppMessage.ts +1 -1
  124. package/src/elements/SwcAppMixin.ts +64 -5
package/README.md CHANGED
@@ -399,16 +399,20 @@ class ProductList extends HTMLElement {
399
399
  - `@hostSet` - host-ancestor-tree info only (`$host`, `$parentHost`, `$hosts`, `$appHost`, `$appHosts`, `$firstHost`, `$lastHost`, `$firstAppHost`, `$lastAppHost`)
400
400
  - `@helperHostSet` - `@hostSet` + DOM/window helpers (`$d`, `$w`, `$q`, `$qa`, `$qi`) + `$this`
401
401
  - `@helperSet` - DOM/window helpers only (`$d`, `$w`, `$q`, `$qa`, `$qi`), no host-tree info
402
+ - `@swcAppRouter` - the `Router` instance (`$appHost.router`) directly, no `@inject`/DI container needed; `undefined` outside a `SwcApp` tree
403
+ - `@swcAppSimpleApplication` - the `SimpleApplication` (DI container) instance (`$appHost.simpleApplication`) directly; `undefined` outside a `SwcApp` tree or without a DI container. `@inject` is usually what you want instead — reach for this only when you need the container itself (e.g. `simstanceManager`).
404
+ - `@swcAppHost` - the `SwcApp` host element itself (`$appHost`) directly, when you just need the host and not the whole `HostSet`; `null` outside a `SwcApp` tree (matches `HostSet.$appHost`'s own type, unlike the two above which use optional chaining down to `undefined`)
402
405
 
403
406
  `$w`/`$d` (and the `helper` passed to every decorator's `filter`/`before`/`finally`) come from the element's window, resolved the same way everywhere: its own `@elementDefine({ window })` → the nearest ancestor SWC host's → the global `window`. Route subscribers (`@subscribeSwcAppRouteChange`) and app messages use the SwcApp's runtime `window` instead (the per-request window under SSR).
404
407
 
405
- The same mechanism (and the same 5 decorators, plus two more) also applies to:
406
- - **`@onInitialize`/`@onConnectedBefore`/`@onConnectedAfter`/... lifecycle methods** — can freely mix `@hostSet`/`@helperHostSet`/`@helperSet` with `@inject(...)` on the same method.
408
+ The same mechanism (and the same 8 decorators, plus two more) also applies to:
409
+ - **`@onInitialize`/`@onConnectedBefore`/`@onConnectedAfter`/... lifecycle methods** — can freely mix `@hostSet`/`@helperHostSet`/`@helperSet`/`@swcAppRouter`/`@swcAppSimpleApplication`/`@swcAppHost` with `@inject(...)` on the same method.
407
410
  - **`@subscribeSwcAppRouteChange`** — add `@swcAppRouterEvent` to receive the `RouterEventType` regardless of position.
408
- - **`@subscribeSwcAppMessage`** — add `@appMessage` to receive the `SwcAppMessage` regardless of position.
409
- - **`before` hook results** — `@eventBeforeReturn`, `@routeChangeBeforeReturn`, `@appMessageBeforeReturn`, `@changedAttributeBeforeReturn`, `@mutationObserverBeforeReturn`, `@resizeObserverBeforeReturn`, `@intersectionObserverBeforeReturn`, `@eventMediaBeforeReturn`, `@setIntervalBeforeReturn`, `@setTimeoutBeforeReturn` inject the value returned by that decorator's `before` option.
411
+ - **`@subscribeSwcAppMessage`** — add `@swcAppMessage` to receive the `SwcAppMessage` regardless of position.
412
+ - **`before` hook results** — `@eventBeforeReturn`, `@routeChangeBeforeReturn`, `@swcAppMessageBeforeReturn`, `@changedAttributeBeforeReturn`, `@mutationObserverBeforeReturn`, `@resizeObserverBeforeReturn`, `@intersectionObserverBeforeReturn`, `@eventMediaBeforeReturn`, `@setIntervalBeforeReturn`, `@setTimeoutBeforeReturn` inject the value returned by that decorator's `before` option.
413
+ - **DOM/storage/fetch values** — `@querySelectorParam`, `@attributeParam`, `@localStorageParam`/`@sessionStorageParam`/`@cookieParam`/`@indexedDbParam`, `@fetchParam` go a step further and actively compute/fetch a value instead of just handing you context — see "Value-Injecting Parameter Decorators" below.
410
414
 
411
- Note: once any parameter of a method is decorated, only decorated parameters receive values (the legacy positional arguments are no longer passed).
415
+ Note: once any parameter of a method is decorated, every parameter still gets a value — decorated ones receive their injected value, and any parameter left undecorated falls back to its legacy positional argument. So mixing is safe: `onChanged(nv, @querySelectorParam('#x') el, name)` still gets `nv`/`name` from the usual positional arguments.
412
416
 
413
417
  ```typescript
414
418
  @onConnectedAfter
@@ -418,7 +422,7 @@ onconstructor(@inject(UserService.SYMBOL) userService: UserService, @hostSet hs:
418
422
  onRouteChanged(@helperSet helpers: HelperSet, @swcAppRouterEvent re: RouterEventType) { ... }
419
423
 
420
424
  @subscribeSwcAppMessage
421
- onMessage(@hostSet hs: HostSet, @appMessage msg: SwcAppMessage) { ... }
425
+ onMessage(@hostSet hs: HostSet, @swcAppMessage msg: SwcAppMessage) { ... }
422
426
  ```
423
427
 
424
428
  #### @emitCustomEvent
@@ -618,7 +622,8 @@ class ProductCard extends HTMLElement {
618
622
  - A field getter evaluates a `{{= expr }}` attribute value (see "Attribute Expressions")
619
623
 
620
624
  #### @removeAttribute (Method Decorator)
621
- Always removes the attribute when the method runs. The return value passes through unchanged,
625
+ Always removes the attribute when the method runs — the name already says what to do, so the return value doesn't matter.
626
+ With `valueKey`, it removes only when that key is truthy. The return value passes through unchanged,
622
627
  so it is safe on subscriber handlers that must not return a value (e.g. route changes).
623
628
 
624
629
  ```typescript
@@ -891,6 +896,20 @@ class ContentUpdater extends HTMLElement {
891
896
  - `@innerHtml` / `@innerHtmlLight` / `@innerHtmlShadow` - Set innerHTML
892
897
  - `@innerText` / `@innerTextLight` / `@innerTextShadow` - Set innerText
893
898
  - `@clearChildrenNode` / `@clearChildrenLight` - Remove all children
899
+ - `@removeNode` - Remove the target element itself (bare / `'$this'` removes the component)
900
+
901
+ **Declaration = action** (`@removeNode`, `@clearChildrenNode`, `@removeAttribute`, and `@addClass` / `@removeClass` / `@toggleClass` with the class name written in the decorator):
902
+ they run whatever the method returns. Give a `valueKey` to decide per call — then they run only when that key is truthy
903
+ (`@toggleClass('.x', 'open')`: no return toggles, `true` / `false` forces on / off).
904
+
905
+ ```typescript
906
+ @eventClick('.close')
907
+ @removeNode('.toast') // always removes
908
+ close() {}
909
+
910
+ @removeNode('.editor', { valueKey: 'close' }) // removes only when close is truthy
911
+ save() { return { close: this.saved }; }
912
+ ```
894
913
  - Options: `position`, `root`, `filter`, `fallback`, `valueKey`. Ready-made `filter` helpers: `skipIfSameTagPresent`, `skipIfExists(selector)`, `skipIfEmpty`, `applyIfChanged` (e.g. `@innerHtmlLight({ filter: skipIfExists('my-page') })`)
895
914
 
896
915
  **Position Options:**
@@ -957,7 +976,7 @@ class StyledComponent extends HTMLElement {
957
976
  **@applyClass Variants:** (each takes `(selector?, classMapOrOptions?, options?)`; bare form targets `$this`)
958
977
  - `setClass` - Replace all classes
959
978
  - `updateClass` - Toggle classes by a `{ className: boolean }` map
960
- - `addClass` / `removeClass` / `toggleClass`
979
+ - `addClass` / `removeClass` / `toggleClass` — with the class name in the decorator (`@addClass('.x', 'on')`) the declaration is the action (see "Declaration = action" above)
961
980
  - `applyClass(selector, action?)` / `cls` - action `'set' | 'update' | 'add' | 'remove' | 'toggle'` (default `'update'`); `clsAppHost` / `clsLight` / `clsShadow` / `clsAll` (for $this use bare `@setClass` / `@updateClass` / `@addClass` / `@removeClass` / `@toggleClass`)
962
981
  - Note: for the class decorators, an options object in the 2nd position must contain `root` (e.g. `{ root: 'auto', valueKey: 'k' }`); an object without `root` is read as a class map
963
982
 
@@ -1158,7 +1177,11 @@ class NotificationPanel extends HTMLElement {
1158
1177
  }
1159
1178
  ```
1160
1179
 
1161
- **@subscribeSwcAppMessage Options:** `filter(message, currentThis)`, `before(message, currentThis)` (result → `@appMessageBeforeReturn`), `finally(message, currentThis, { args, result, error })`, `subject`, `trigger` (see "Message Replay"). Every matching subscriber runs (fire-and-forget); return values do not stop other subscribers.
1180
+ **@subscribeSwcAppMessage Options:** `filter(message, currentThis)`, `before(message, currentThis)` (result → `@swcAppMessageBeforeReturn`), `finally(message, currentThis, { args, result, error })`, `subject`, `trigger` (see "Message Replay"). Every matching subscriber runs (fire-and-forget); return values do not stop other subscribers.
1181
+
1182
+ **Shortcuts for `subject`:** `@subscribeSwcAppMessageBehavior(type, options?)` = `{ subject: 'behavior' }` (a late subscriber gets the last message),
1183
+ `@subscribeSwcAppMessageReplay(type, options?)` = `{ subject: 'replay' }` (gets the whole buffer). Same forms as `@subscribeSwcAppMessage`
1184
+ (bare, type, options, type + options); the other options pass through.
1162
1185
 
1163
1186
  #### @publishSwcAppMessage
1164
1187
  Publish a message from a method's return value.
@@ -1485,9 +1508,25 @@ No prefix means *first*; `First`/`Last` pick the first/last value when a key rep
1485
1508
  load(@swcAppRoutePathVariable('releaseSeq') seq: string, @swcAppRouteQueryParam('tab') tab: string | null) { ... }
1486
1509
  ```
1487
1510
 
1488
- - Once any parameter is decorated, the positional route argument is no longer passed — add `@swcAppRouterEvent` for the whole event.
1511
+ - Add `@swcAppRouterEvent` for the whole event — any parameter left undecorated still gets the positional route argument even after others are decorated (see the parameter-decorator note earlier in this doc).
1489
1512
  - `route.pathData` keeps its old behavior: a repeated variable name holds the **last** value. Use the decorators above to pick first/last explicitly.
1490
1513
 
1514
+ **On fields.** The same decorators work on fields. The SwcApp fills them on every route change and, for an element attached later, from the current route before its first render. Inside a route handler of the same element, the field already holds this route's value.
1515
+
1516
+ ```typescript
1517
+ class UserPage extends HTMLElement {
1518
+ @swcAppRouteQueryParam('tab') tab?: string | null; // query: no pattern needed
1519
+ @swcAppRoutePathVariable('id', { path: '/user/{id}' }) userId?: string; // path variables need { path }
1520
+ @swcAppRoutePathVariableObject({ path: ['/user/{id}', '/member/{id}'] }) vars?: { id?: string };
1521
+
1522
+ @onConnectedBodyShadow render() { return `<h1>${this.userId} · ${this.tab}</h1>`; }
1523
+ }
1524
+ ```
1525
+
1526
+ - `path` takes the same forms as `@subscribeSwcAppRouteChange` (string, array, or `(currentThis) => ...`). When it doesn't match the current route, path fields are empty (`undefined`, `[]`, `{}`); query fields keep updating. A path-variable field without `{ path }` warns once at definition.
1527
+ - A field is reassigned only when its value changes (object fields keep their reference otherwise), so a setter on it doesn't fire for unrelated route changes.
1528
+ - Don't name such fields after built-in `HTMLElement` properties (`id`, `lang`, `title`, `prefix`, ...): assigning to them changes the element instead.
1529
+
1491
1530
  **6. Navigating: `@swcAppRoute` / `@swcAppRouteGo`**
1492
1531
 
1493
1532
  The method returns where to go; the decorator calls the element's SwcApp router — no `Router` injection needed. `@swcAppRoute({ type })` picks the Router method (default `'go'`); `@swcAppRouteGo`, `@swcAppRoutePush`, ... are aliases with the type fixed.
@@ -1953,6 +1992,40 @@ constructor(private service: Service) { super(); } // Web Components can't have
1953
1992
 
1954
1993
  ---
1955
1994
 
1995
+ ## ⚡ Benchmarks
1996
+
1997
+ Measured in real Chrome against a hand-written `innerHTML` renderer and Lit, rendering the same 1,000-row table (state in fields, a decorated method returns the HTML, `@replaceChildren*` applies it):
1998
+
1999
+ - **Bulk rendering keeps up with Lit.** Creating 10,000 rows takes 244 ms, versus 232 ms for Lit and 222 ms for a hand-written `innerHTML` loop.
2000
+ - **Low memory.** 1,000 rows keep about 94 KB of JS heap, 6x less than Lit (558 KB); at 10,000 rows it is 1.6 MB versus 4.9 MB (3x less). Only the data is retained, no per-row template bookkeeping.
2001
+ - **Thin layer.** Rendering through the decorators costs within about 5% to 25% of the equivalent hand-written `innerHTML` code.
2002
+
2003
+ ```text
2004
+ create 10,000 rows (lower is better)
2005
+ vanilla (innerHTML) ██████████████████████████ 222 ▲
2006
+ lit ████████████████████████████ 232
2007
+ simple-web-component █████████████████████████████ 244
2008
+ vanilla (DOM calls) ████████████████████████████████ 269
2009
+
2010
+ JS heap, 1,000 rows (KB) (lower is better)
2011
+ vanilla (innerHTML) ████ 73.4 ▲
2012
+ simple-web-component █████ 93.5
2013
+ vanilla (DOM calls) ███████ 119
2014
+ lit ████████████████████████████████ 558
2015
+ ```
2016
+
2017
+ Full results, including the operations where other approaches are faster, methodology and caveats: [bench/RESULTS.md](./bench/RESULTS.md). Reproduce with `pnpm bench` inside `bench/`.
2018
+
2019
+ ---
2020
+
2021
+ ## 🧰 Editor Support (LSP)
2022
+
2023
+ The package ships a language server for SWC templates — `npx swc-lsp --stdio`:
2024
+ tag / attribute / `@state@` / `$host.` completion, hover, go to definition, parameter hints, and type errors inside `swc-on-*`, `{{= }}` and `@x@`
2025
+ (`swc-on-click="$host.tt(4)"` → *number is not assignable to string*).
2026
+
2027
+ Setup for IntelliJ, VS Code and Neovim: [lsp/README.md](https://github.com/dooboostore-develop/packages/tree/main/@dooboostore/simple-web-component/lsp).
2028
+
1956
2029
  ## 🧪 Testing
1957
2030
 
1958
2031
  `pnpm test` type-checks the tests and runs them in a real browser (Chromium via Playwright, falling back to the installed Chrome) — no jsdom. Each test gets its own same-origin iframe window, so custom elements, `history` and `location` never leak between tests.
@@ -1999,8 +2072,8 @@ Late subscribers can receive past messages. The buffer keeps every typed message
1999
2072
  ```typescript
2000
2073
  // 'behavior' = last message only, 'replay' = whole buffer in order.
2001
2074
  // Unset (or 'subject') = live only.
2002
- @subscribeSwcAppMessage('auth-changed', { subject: 'behavior' })
2003
- onAuth(@appMessage msg: SwcAppMessage<User | null>) { ... }
2075
+ @subscribeSwcAppMessageBehavior('auth-changed') // = @subscribeSwcAppMessage('auth-changed', { subject: 'behavior' })
2076
+ onAuth(@swcAppMessage msg: SwcAppMessage<User | null>) { ... }
2004
2077
  ```
2005
2078
 
2006
2079
  `trigger` controls when replay happens (default `'connected'`).
@@ -2014,12 +2087,26 @@ onAuth(@appMessage msg: SwcAppMessage<User | null>) { ... }
2014
2087
  ```typescript
2015
2088
  @subscribeSwcAppMessage('auth-changed', { subject: 'behavior', trigger: 'connectedDone' })
2016
2089
  @innerHtml('.wrap')
2017
- async load(@appMessage msg: SwcAppMessage<User | null>) { ... }
2090
+ async load(@swcAppMessage msg: SwcAppMessage<User | null>) { ... }
2018
2091
  ```
2019
2092
 
2020
2093
  Route subscribers (`@subscribeSwcAppRouteChange`) accept the same `trigger`.
2021
2094
  Live broadcasts always reach everyone regardless of trigger.
2022
2095
 
2096
+ ### `@swcAppMessage` on fields
2097
+
2098
+ On a field, `@swcAppMessage` holds the latest `SwcAppMessage` — set on every publish, before the same element's subscribers run. It takes the same forms and `subject` rule as `@subscribeSwcAppMessage`:
2099
+
2100
+ ```typescript
2101
+ @swcAppMessage last?: SwcAppMessage; // every type, live only
2102
+ @swcAppMessage('auth-changed') auth?: SwcAppMessage<User | null>; // live only (default 'subject')
2103
+ @swcAppMessage('auth-changed', { subject: 'behavior' }) me?: SwcAppMessage<User | null>; // late element: last one
2104
+ @swcAppMessage({ messageType: 'auth-changed', subject: 'replay' }) all?: SwcAppMessage; // late element: buffer in order
2105
+ ```
2106
+
2107
+ - With `'behavior'`/`'replay'` (and a type), an element attached after the publish gets the field filled from the buffer before its first render. Without a type nothing is replayed.
2108
+ - `@swcAppMessageBeforeReturn` stays parameter-only: it is the `before` hook's result for one handler call.
2109
+
2023
2110
  ## 🔌 App Host Hooks (onConnected / onSwcAppConnected / onDisconnected)
2024
2111
 
2025
2112
  The three host hooks of `SwcAppMixin` are **abstract**: a subclass must implement them (use an empty method if there is nothing to do).
@@ -2064,37 +2151,119 @@ Use `connectedElements()` to get the currently connected child elements.
2064
2151
 
2065
2152
  ## 🌐 @fetch — Declarative HTTP
2066
2153
 
2154
+ `@fetch` and its aliases (`@fetchGet`, `@fetchPost`, `@fetchLatest`, `@fetchManual`, …) go in one of three places.
2155
+ Pick by **who calls it** and **whether the result should be remembered**:
2156
+
2157
+ | Where | Declare | Use when | Remembers the result? |
2158
+ |---|---|---|---|
2159
+ | **Method** | `load(@fetchPromise p: Promise<T>) { … }` | the framework calls it — a trigger handler (`@eventClick`, `@onConnectedAfter`, a route…) | no |
2160
+ | **Function field** | `declare getPost: (id: number) => Promise<T>;` | you call it yourself, anywhere, maybe with arguments (`this.getPost(1)`) | no — every call is a new request |
2161
+ | **Value field** | `declare me?: Promise<T>;` | data you load once and keep reading (`await this.me`) | **yes** — until you clear it |
2162
+
2163
+ ### 1. On a method — trigger handlers
2164
+
2165
+ Stack the trigger, the outputs and `@fetch` on one method. The request starts first; its `Promise` is handed to the
2166
+ `@fetchPromise` parameter and the method runs **right away**. The method's own return value is returned unchanged, so the
2167
+ signature you wrote stays true (a sync method stays sync).
2168
+
2067
2169
  ```typescript
2068
- // bare form: GET by default
2069
- @fetch('https://api.example.com/post/1')
2070
- async load(@fetchSettled settled: PromiseSettledResult<any>) {
2071
- return settled;
2170
+ @eventClick('.load')
2171
+ @innerHtml('.out', { fallback: () => 'Loading…' }) // shown until the returned Promise settles
2172
+ @fetchLatest('/api/post/1') // click again → the previous request is aborted
2173
+ load(@fetchPromise p: Promise<Post>) {
2174
+ return p.then(post => post.title, () => 'Failed'); // success / failure, no try/catch
2072
2175
  }
2176
+ ```
2073
2177
 
2074
- // before (default): build request → fetch → inject settled → run method.
2075
- // Returns the method result.
2076
- @fetch({ url: '/api/post/1', request: 'GET' })
2077
- async loadBefore(@fetchSettled settled: PromiseSettledResult<any>) {
2078
- return settled.status === 'fulfilled' ? settled.value : null;
2079
- }
2178
+ If you also call such a method yourself, declare the parameter optional (`@fetchPromise p?: Promise<T>`) — the
2179
+ framework fills it, callers don't. For a request you call yourself, a field (below) is the better fit.
2080
2180
 
2081
- // after: run method → use its return value as the body → fetch. Returns the fetch result.
2082
- @fetch({ url: '/api/posts', trigger: 'after', process: 'json' })
2083
- async save() {
2084
- return { title: 'hello' };
2085
- }
2181
+ ### 2. Function field — a request function you call
2182
+
2183
+ The framework writes the function body; the declared type is the real signature (no injected parameter, no changed
2184
+ return type).
2086
2185
 
2087
- // after + valueKey: use returnValue[valueKey] as the body.
2088
- @fetch({ url: '/api/echo', trigger: 'after', valueKey: 'form', process: 'form' })
2089
- async saveForm() {
2090
- return { form: { title: 'hi' } };
2186
+ ```typescript
2187
+ // GET / DELETE: the arguments feed url / request
2188
+ @fetchGet((_self, _helper, [id]) => `/api/posts/${id}`)
2189
+ declare getPost: (id: number) => Promise<Post>;
2190
+
2191
+ // POST / PUT / PATCH: the last argument is the body
2192
+ @fetchPost('/api/posts', { process: 'json' })
2193
+ declare createPost: (body: NewPost) => Promise<Post>;
2194
+
2195
+ @fetchLatest({ url: (_s, _h, [q]) => `/api/search?q=${q}` }) // only the latest call settles
2196
+ declare search: (q: string) => Promise<Item[]>;
2197
+
2198
+ // use it from a trigger handler (or anywhere)
2199
+ @eventClick('.load')
2200
+ @innerHtml('.out', { fallback: () => 'Loading…' })
2201
+ show() {
2202
+ return this.getPost(1).then(p => p.title);
2091
2203
  }
2092
2204
  ```
2093
2205
 
2094
- **Modes**
2095
- - **before** (default, or `trigger: 'before'`): build request → fetch → inject the settled result via
2096
- `@fetchSettled` → run the method. Returns the method result. A failed fetch does not
2097
- throw — it arrives as `{ status: 'rejected', reason }`.
2206
+ Every call is a new request. Success resolves, failure rejects with `HttpResponseError` (see below).
2207
+
2208
+ ### 3. Value field — data that is remembered
2209
+
2210
+ ```typescript
2211
+ @fetch('/api/me')
2212
+ declare me?: Promise<User>; // `?` so that `this.me = undefined` type-checks under `strict`
2213
+
2214
+ await this.me; // first read: request → remembered on success
2215
+ await this.me; // remembered result (no request)
2216
+
2217
+ this.me = undefined; // forget it (null works too) …
2218
+ await this.me; // … so this read requests again — this is how you reload
2219
+
2220
+ this.me = savedUser; // or seed a value yourself (e.g. data that came with SSR) — no request
2221
+ ```
2222
+
2223
+ - Declare it optional (`declare me?: Promise<T>`) if you ever clear it: under `strict`, assigning `undefined` to a
2224
+ plain `Promise<T>` is a type error. Reading it is still `await this.me` (the result type is `T | undefined`).
2225
+ If you never clear it, `declare me: Promise<T>` is fine.
2226
+ - Clear it by assigning, not with `delete this.me` — the memory lives behind the field's setter.
2227
+
2228
+ - **Remembered**: success, per element. **Not remembered**: failure — the next read requests again.
2229
+ - **Forgotten**: when you assign `undefined` / `null`, and when the element disconnects (the request is aborted; a read
2230
+ after reconnecting requests again).
2231
+ - There are no arguments — build the body in the `request` factory if the request needs one.
2232
+ - If the data must be fresh on every use, declare a function field instead (`declare loadMe: () => Promise<User>`).
2233
+ - The value is a real Promise to your code (`instanceof Promise` is true), so it can be returned straight to an output
2234
+ decorator: `@innerHtml('.name') showName() { return this.me.then(u => u.name); }`.
2235
+
2236
+ ### Field rules (function and value fields)
2237
+
2238
+ - **Always write `declare`.** Without it, builds with `useDefineForClassFields: true` (the default for target ES2022+)
2239
+ create an instance field that hides what the framework put there:
2240
+
2241
+ | Build setting | `declare me: Promise<T>` | `me!: Promise<T>` (no `declare`) |
2242
+ |---|---|---|
2243
+ | `useDefineForClassFields: false` | works | works (but `strict` needs the `!`) |
2244
+ | `useDefineForClassFields: true` / ES2022+ default | works | **broken** — reported on connect: *must be declared with `declare`* |
2245
+
2246
+ - **Declared type is checked.** At compile time the field must be `(...args) => Promise<T>` or `Promise<T>`
2247
+ (`string`, `() => T`, … are errors; optional `?` fields are fine; `private` / `protected` fields can't be seen by
2248
+ TypeScript and are not checked).
2249
+ Builds that emit `design:type` (`emitDecoratorMetadata` with tsc / ts-loader) also reject a non-function, non-Promise
2250
+ type at runtime.
2251
+ - **Nothing else on the field.** Triggers and outputs go on a method that calls the field. Method decorators on a field
2252
+ are already compile errors; any other SWC decorator on the same field (`@attribute`, `@query`, …, or anything via
2253
+ `as any`) throws when the class is defined.
2254
+ - **Same in every build.** Function vs. value is decided by how you declared it, not by build metadata: the field holds
2255
+ one object that is callable and a Promise, and TypeScript lets you use it only the way you declared it.
2256
+ - **Quiet ends.** A call skipped by `filter` or made while the element is detached, and a call aborted by the framework
2257
+ (disconnect, `abortPrevious`), return a Promise that **never settles** — nothing draws on a detached DOM, nothing throws.
2258
+
2259
+ ### Method modes
2260
+
2261
+ - **before** (default, or `trigger: 'before'`): start the request → inject its `Promise` via
2262
+ `@fetchPromise` → run the method **right away**. Returns the method's own return value, so the
2263
+ signature you wrote stays true (sync stays sync). Success resolves, failure rejects — handle both with
2264
+ `then` / `catch` / `finally` on the Promise.
2265
+ If you also call the method yourself, declare the parameter optional (`@fetchPromise p?: Promise<T>`) —
2266
+ the framework fills it, callers don't.
2098
2267
  - **after** (`trigger: 'after'`, or just `valueKey`): run the method → its return value
2099
2268
  (or `returnValue[valueKey]`) becomes the body → fetch. Returns the fetch result; a failed fetch throws.
2100
2269
  `valueKey` is after-only — combining it with `trigger: 'before'` is a type error.
@@ -2107,7 +2276,7 @@ async saveForm() {
2107
2276
  ```typescript
2108
2277
  // service call — only the result matters
2109
2278
  @fetch({ manual: (self) => self.myService.getProfile({}) })
2110
- async load(@fetchSettled settled?: PromiseSettledResult<MyService.ProfileResponse>) { ... }
2279
+ load(@fetchPromise p: Promise<MyService.ProfileResponse>) { ... }
2111
2280
 
2112
2281
  // your own fetch — pass the signal so an abort cancels the network request too
2113
2282
  @fetch({ trigger: 'after', manual: (_self, _helper, _params, signal, returnValue) =>
@@ -2136,38 +2305,37 @@ Its return value is the fetch result.
2136
2305
 
2137
2306
  ```typescript
2138
2307
  @fetch('/api/post/1')
2139
- async load(@fetchSettled settled?: PromiseSettledResult<any>) {
2140
- if (settled?.status === 'rejected' && isHttpResponseError(settled.reason)) {
2141
- return settled.reason.response?.status; // e.g. 404
2142
- }
2308
+ load(@fetchPromise p: Promise<Post>) {
2309
+ return p.catch(e => isHttpResponseError(e) ? e.response?.status : undefined); // e.g. 404
2143
2310
  }
2144
2311
  ```
2145
2312
 
2146
- **Hooks** (same order as every other SWC decorator: `filter → before → handler → finally`)
2147
- - `filter(this, helper, params)` → `false` skips the whole call (no method, no fetch; returns `undefined`).
2148
- - `before(this, helper, params)` runs first after `filter` and is awaited; its return value is ignored.
2149
- - `after(this, helper, params, settled)` runs right after the fetch settles (fulfilled or rejected).
2150
- - `finally(this, helper, params, { args, result, error })` always runs around the whole call.
2151
- `result` is what the call returns (the method result in before mode, the fetch result in after mode).
2313
+ **filter** — the only hook
2314
+ - `filter({ self, helper, args })` → `false` skips the whole call: no request, no method. A method returns `undefined`;
2315
+ a field returns a Promise that never settles.
2316
+ It is synchronous: the request starts before the method runs, so "send or not" can only be decided here.
2317
+ - There is no `before` / `after` / `finally` on `@fetch`: result handling is plain Promise code
2318
+ (`then` / `catch` / `finally`), and gating or cleanup around the call lives on the trigger you stack it with
2319
+ (`@eventClick`, `@onConnectedAfter`, …), which already has `filter → before → handler → finally`.
2152
2320
 
2153
2321
  **Cancellation**
2154
2322
  - Every call gets its own `AbortController`. Declarative requests get its signal as `init.signal`
2155
2323
  (merged with a `signal` you return from `request`, via `AbortSignal.any` or a fallback); `manual` gets it as
2156
2324
  the `signal` argument.
2157
- - When the element disconnects, all its in-flight `@fetch` requests are aborted. Such a call ends
2158
- quietly with `undefined`: the method (before mode) and the `after` hook are skipped so nothing touches
2159
- a detached DOM; `finally` still runs with `ctx.error` set to the `AbortError`.
2325
+ - When the element disconnects, all its in-flight `@fetch` requests are aborted. The injected Promise then
2326
+ **never settles** (before mode), so nothing draws on a detached DOM and nothing throws; an after-mode call
2327
+ ends quietly with `undefined`.
2160
2328
  - A call that *starts* while the element is detached (e.g. a `setTimeout` scheduled just before the user
2161
2329
  navigated away) is skipped the same quiet way. Elements that were never connected are not affected.
2162
2330
  - `manual` should pass `signal` on to its own client (`fetch`, axios, ...) so the network
2163
2331
  request is actually cancelled. If it ignores the signal, the call still ends as soon as it's aborted
2164
2332
  (the result is raced against the abort) — the request just keeps running in the background and its
2165
2333
  late result is discarded.
2166
- - `abortPrevious: true` aborts the previous in-flight call of the same method when it's called again
2167
- (search-as-you-type) — the superseded call ends quietly the same way, so a late old response can't
2334
+ - `abortPrevious: true` aborts the previous in-flight call of the same method (per element) when it's called again
2335
+ (search-as-you-type) — the superseded Promise never settles, so a late old response can't
2168
2336
  overwrite the newest result.
2169
- - Aborting through your own signal is not quiet: it surfaces as a rejected settled result (before mode)
2170
- or a thrown error (after mode), like any other failure.
2337
+ - Aborting through your own signal is not quiet: it rejects the Promise (before mode)
2338
+ or throws (after mode), like any other failure.
2171
2339
 
2172
2340
  **Aliases**
2173
2341
 
@@ -2183,13 +2351,13 @@ For the method aliases, `request` may only be a factory returning `RequestInit`
2183
2351
 
2184
2352
  ```typescript
2185
2353
  @fetchManual((self) => self.myService.getProfile({}))
2186
- async load(@fetchSettled settled?: PromiseSettledResult<Profile>) { ... }
2354
+ load(@fetchPromise p: Promise<Profile>) { ... }
2187
2355
 
2188
2356
  @fetchPost('/api/posts', { process: 'json' })
2189
2357
  async save() { return { title: 'hi' }; }
2190
2358
 
2191
2359
  @fetchDelete((_self, _helper, params) => `/api/posts/${params[0]}`)
2192
- async remove(id: number, @fetchSettled settled?: PromiseSettledResult<unknown>) { ... }
2360
+ remove(id: number, @fetchPromise p?: Promise<unknown>) { ... }
2193
2361
  ```
2194
2362
 
2195
2363
  **Composition** — e.g. form submit:
@@ -2197,6 +2365,124 @@ async remove(id: number, @fetchSettled settled?: PromiseSettledResult<unknown>)
2197
2365
  stacked on `@fetch({ url: '/api/echo', trigger: 'after', process: 'form' })`, with the method taking
2198
2366
  `@eventBeforeReturn formData: FormData` and returning it.
2199
2367
 
2368
+ ## 🧩 Value-Injecting Parameter Decorators (@querySelectorParam, @attributeParam, @local/session/cookie/indexedDbParam, @fetchParam, @swcAppRouter)
2369
+
2370
+ Unlike `@hostSet`/`@helperSet`/`@helperHostSet` (which just hand you context objects), these decorators actively **go compute or fetch a value** and inject it — once, at the moment the method's trigger fires (`@onConnectedAfter` and friends, `@addEventListener`, `@setInterval`/`@setTimeout`, the observer decorators, `@eventMedia`, route/message subscribers, ...). They only work inside such auto-triggered methods — a plain method you call yourself gets `undefined` for these parameters, since nothing builds the lookup for it.
2371
+
2372
+ > Unlike `@query`/`@queryAll` (lazy — re-queries the DOM on every read), these resolve **once per call**, as a plain captured value, not a live reference. If the DOM/storage changes after the method runs, the parameter you already received does not change.
2373
+
2374
+ ### @querySelectorParam / @querySelectorAllParam
2375
+ Same engine as the field decorators `@query`/`@queryAll` (`root`, `pick`, `filter`, function selectors all supported) — named "querySelector" instead of "query" so it doesn't read like a URL query parameter.
2376
+
2377
+ ```typescript
2378
+ @onConnectedAfter
2379
+ onReady(
2380
+ @querySelectorParam('#name') input: HTMLInputElement,
2381
+ @querySelectorAllParam('.item', { root: 'all' }) items: HTMLElement[]
2382
+ ) {
2383
+ input.focus();
2384
+ }
2385
+
2386
+ @addEventListener('#save', 'click')
2387
+ onSave(@querySelectorShadowParam('.form') form: HTMLFormElement) { ... }
2388
+ ```
2389
+ - Root/pick shorthands mirror `@query`'s own family: `querySelectorShadowParam` / `querySelectorLightParam` / `querySelectorAllRootsParam` (single), `querySelectorAllShadowParam` / `querySelectorAllLightParam` / `querySelectorAllAllParam` (arrays).
2390
+
2391
+ ### @attributeParam
2392
+ Same engine as the field/method `@attribute`.
2393
+
2394
+ ```typescript
2395
+ onReady(
2396
+ @attributeParam('data-x') ownAttr: string,
2397
+ @attributeParam('#child', 'data-y', { root: 'shadow' }) childAttr: string
2398
+ ) { ... }
2399
+ ```
2400
+ - One string = this element's own attribute; `(selector, name, options?)` = another element's attribute (same two-form shape as the field decorator).
2401
+ - `options.type` converts to `Number`/`Boolean`, same as the field decorator; missing attribute/target → `null`.
2402
+
2403
+ ### @localStorageParam / @sessionStorageParam / @cookieParam / @indexedDbParam
2404
+ Inject a persisted value by key (see "Persisted State" below for the backing storage). `@indexedDbParam` is async, so it injects a **Promise** rather than the resolved value — the surrounding resolution has to stay synchronous:
2405
+
2406
+ ```typescript
2407
+ onReady(
2408
+ @localStorageParam('theme') theme: string,
2409
+ @indexedDbParam('draft') draftPromise: Promise<string>
2410
+ ) {
2411
+ this.applyTheme(theme);
2412
+ draftPromise.then(d => this.restoreDraft(d));
2413
+ }
2414
+ ```
2415
+
2416
+ ### @fetchParam
2417
+ A minimal fetch — no abort-on-disconnect, no `abortPrevious`, no `filter` (reach for `@fetch`/`@fetchManual` + `@fetchPromise` when you need those). It injects a **Promise** that resolves to the parsed JSON/text body, or rejects with an `Error` on a non-OK status.
2418
+
2419
+ ```typescript
2420
+ @onConnectedAfter
2421
+ async onReady(@fetchParam('/api/products/1') p: Promise<Product>) {
2422
+ this.product = await p;
2423
+ }
2424
+
2425
+ // url/init accept (currentThis, helper) => ... callbacks too, same shape as @fetch's factories —
2426
+ // handy for referencing instance fields to build a dynamic URL or body.
2427
+ @addEventListener('#save', 'click')
2428
+ async onSave(@fetchParam(
2429
+ (self) => `/api/products/${self.productId}`,
2430
+ (self) => ({ method: 'POST', body: JSON.stringify({ qty: self.qty }) })
2431
+ ) p: Promise<any>) {
2432
+ await p;
2433
+ }
2434
+ ```
2435
+
2436
+ ### @swcAppRouter / @swcAppSimpleApplication / @swcAppHost
2437
+ Documented above alongside `@hostSet`/`@helperSet` — these just hand you a context reference (the `Router`, the DI container, or the `SwcApp` host element itself), they don't compute anything the way the rest of this section's decorators do.
2438
+
2439
+ ## 💾 Persisted State (@localStorage, @sessionStorage, @cookie, @indexedDb, @persistState)
2440
+
2441
+ Field or method decorator that mirrors a value to a storage backend. Survives disconnect/reconnect and page reloads — the whole point is that **element lifecycle never clears it**; only you do (see "Removing a key" below).
2442
+
2443
+ ```typescript
2444
+ class Settings extends HTMLElement {
2445
+ // Field — bare key defaults to the field name; the stored value wins over the initializer on reconnect
2446
+ @localStorage theme: string = 'dark';
2447
+
2448
+ // Explicit key
2449
+ @sessionStorage('draft-id') draftId?: string;
2450
+
2451
+ @cookie('session-token', { maxAge: 3600, sameSite: 'Strict' })
2452
+ token?: string;
2453
+
2454
+ // Method — persists the return value (JSON-serialized) each time it runs
2455
+ @localStorage('last-search')
2456
+ search(q: string) { return q; }
2457
+ }
2458
+ ```
2459
+
2460
+ - **Field**: getter/setter. Reading re-hydrates from storage on first access; assigning writes through. Assigning `undefined` **removes** the key (and clears the in-memory value too).
2461
+ - **Method**: the return value is persisted after the method runs (`valueKey` picks one field out of an object return).
2462
+ - Backends: `local` / `session` / `cookie` (sync) and `indexeddb` (async). The generic form is `@persistState(key?, { storage, ... })`; `@localStorage`/`@sessionStorage`/`@cookie`/`@indexedDb` are storage-fixed aliases.
2463
+ - `@indexedDb` on a field: reading can't `await`, so the first read returns the initializer immediately and the stored value lands right after (a console warning flags this once per class) — prefer calling `persistReadAsync` directly, or a `Promise`-typed field, for async backends.
2464
+ - Options: `valueKey`, `serialize`/`deserialize` (default `JSON.stringify`/`JSON.parse`); `cookie` also takes `path`/`domain`/`maxAge`/`expires`/`secure`/`sameSite`.
2465
+
2466
+ **Removing a key**
2467
+ ```typescript
2468
+ class Settings extends HTMLElement {
2469
+ @localStorage theme: string = 'dark';
2470
+
2471
+ @removeLocalStorage('theme')
2472
+ clearTheme() {}
2473
+ }
2474
+ ```
2475
+ - `@removeLocalStorage` / `@removeSessionStorage` / `@removeCookie` / `@removeIndexedDb` (method-only) — call them, or just assign `undefined` to the field directly (`this.theme = undefined`), which does the same thing and also clears the live value.
2476
+ - Generic form: `@removePersistState(key?, options?)`.
2477
+
2478
+ **Direct function access** (no decorator needed) — for a plain method body, or the async backend:
2479
+ ```typescript
2480
+ import { persistRead, persistWrite, persistRemove, persistReadAsync, persistWriteAsync, persistRemoveAsync } from '@dooboostore/simple-web-component';
2481
+
2482
+ const cached = persistRead(this, 'theme', { storage: 'local' });
2483
+ const draft = await persistReadAsync(this, 'draft', { storage: 'indexeddb' });
2484
+ ```
2485
+
2200
2486
  ## 💧 @property Hydration Rules
2201
2487
 
2202
2488
  - Attach bare `@property` (no args) to a field to mark it as an SSR hydration target.
@@ -920,6 +920,21 @@ __export(addEventListener_exports, {
920
920
  eventTransitionstartMutationShadow: () => eventTransitionstartMutationShadow,
921
921
  eventTransitionstartShadow: () => eventTransitionstartShadow,
922
922
  eventTransitionstartWindow: () => eventTransitionstartWindow,
923
+ eventVisibilitychange: () => eventVisibilitychange,
924
+ eventVisibilitychangeAll: () => eventVisibilitychangeAll,
925
+ eventVisibilitychangeAppHost: () => eventVisibilitychangeAppHost,
926
+ eventVisibilitychangeDelegate: () => eventVisibilitychangeDelegate,
927
+ eventVisibilitychangeDelegateAll: () => eventVisibilitychangeDelegateAll,
928
+ eventVisibilitychangeDelegateLight: () => eventVisibilitychangeDelegateLight,
929
+ eventVisibilitychangeDelegateShadow: () => eventVisibilitychangeDelegateShadow,
930
+ eventVisibilitychangeDocument: () => eventVisibilitychangeDocument,
931
+ eventVisibilitychangeLight: () => eventVisibilitychangeLight,
932
+ eventVisibilitychangeMutation: () => eventVisibilitychangeMutation,
933
+ eventVisibilitychangeMutationAll: () => eventVisibilitychangeMutationAll,
934
+ eventVisibilitychangeMutationLight: () => eventVisibilitychangeMutationLight,
935
+ eventVisibilitychangeMutationShadow: () => eventVisibilitychangeMutationShadow,
936
+ eventVisibilitychangeShadow: () => eventVisibilitychangeShadow,
937
+ eventVisibilitychangeWindow: () => eventVisibilitychangeWindow,
923
938
  eventWheel: () => eventWheel,
924
939
  eventWheelAll: () => eventWheelAll,
925
940
  eventWheelAppHost: () => eventWheelAppHost,
@@ -2005,6 +2020,22 @@ const eventToggleAll = toggleAliases.all;
2005
2020
  const eventToggleAppHost = toggleAliases.appHost;
2006
2021
  const eventToggleWindow = toggleAliases.window;
2007
2022
  const eventToggleDocument = toggleAliases.document;
2023
+ const visibilitychangeAliases = makeTypedEventAliases("visibilitychange");
2024
+ const eventVisibilitychange = visibilitychangeAliases.base;
2025
+ const eventVisibilitychangeDelegateLight = visibilitychangeAliases.delegateLight;
2026
+ const eventVisibilitychangeDelegateShadow = visibilitychangeAliases.delegateShadow;
2027
+ const eventVisibilitychangeDelegateAll = visibilitychangeAliases.delegateAll;
2028
+ const eventVisibilitychangeDelegate = visibilitychangeAliases.delegate;
2029
+ const eventVisibilitychangeMutationLight = visibilitychangeAliases.mutationLight;
2030
+ const eventVisibilitychangeMutationShadow = visibilitychangeAliases.mutationShadow;
2031
+ const eventVisibilitychangeMutationAll = visibilitychangeAliases.mutationAll;
2032
+ const eventVisibilitychangeMutation = visibilitychangeAliases.mutation;
2033
+ const eventVisibilitychangeLight = visibilitychangeAliases.light;
2034
+ const eventVisibilitychangeShadow = visibilitychangeAliases.shadow;
2035
+ const eventVisibilitychangeAll = visibilitychangeAliases.all;
2036
+ const eventVisibilitychangeAppHost = visibilitychangeAliases.appHost;
2037
+ const eventVisibilitychangeWindow = visibilitychangeAliases.window;
2038
+ const eventVisibilitychangeDocument = visibilitychangeAliases.document;
2008
2039
  const getAddEventListenerMetadata = (target) => {
2009
2040
  const constructor = typeof target === "function" ? target : target.constructor;
2010
2041
  return import_core.ReflectUtils.findAllMetadata(ADD_EVENT_LISTENER_METADATA_KEY, constructor).flat();
@@ -2054,16 +2085,12 @@ class EventListenerLifeCycler {
2054
2085
  if (options.stopPropagation) event2.stopPropagation();
2055
2086
  if (options.stopImmediatePropagation) event2.stopImmediatePropagation();
2056
2087
  if (options.preventDefault) event2.preventDefault();
2057
- const currentHostSet = import_Utils.SwcUtils.getHostSet(inst);
2058
- const legacyArgs = [event2, { currentHostSet, $matchedElement: matchedElement }, { event: event2, ...currentHostSet, $el: target, $root: target }];
2059
- const currentHelperSet = import_Utils.SwcUtils.getHelperSet(currentWin);
2060
- const currentHelperHostSet = { ...currentHelperSet, ...currentHostSet, $this: inst };
2088
+ const common = (0, import_parameter.buildCommonKindValues)(inst, currentWin);
2089
+ const legacyArgs = [event2, { currentHostSet: common.hostSet, $matchedElement: matchedElement }, { event: event2, ...common.hostSet, $el: target, $root: target }];
2061
2090
  const buildArgs = (beforeReturn) => (0, import_parameter.buildSwcParameterArgs)(inst, meta.propertyKey, {
2091
+ ...common,
2062
2092
  eventObject: event2,
2063
2093
  matchedElement,
2064
- hostSet: currentHostSet,
2065
- helperHostSet: currentHelperHostSet,
2066
- helperSet: currentHelperSet,
2067
2094
  eventBeforeReturn: beforeReturn
2068
2095
  }, legacyArgs);
2069
2096
  let args = buildArgs(void 0);
@@ -2199,16 +2226,12 @@ class EventListenerLifeCycler {
2199
2226
  if (m.options.stopPropagation) event2.stopPropagation();
2200
2227
  if (m.options.stopImmediatePropagation) event2.stopImmediatePropagation();
2201
2228
  if (m.options.preventDefault) event2.preventDefault();
2202
- const hs = import_Utils.SwcUtils.getHostSet(inst);
2203
- const legacyArgs = [event2, { ...hs, $matchedElement: matchedEl }, { event: event2, ...hs, $el: matchedEl, $root: br }];
2204
- const helperSetForMatch = import_Utils.SwcUtils.getHelperSet(currentWin);
2205
- const helperHostSetForMatch = { ...helperSetForMatch, ...hs, $this: inst };
2229
+ const common = (0, import_parameter.buildCommonKindValues)(inst, currentWin);
2230
+ const legacyArgs = [event2, { ...common.hostSet, $matchedElement: matchedEl }, { event: event2, ...common.hostSet, $el: matchedEl, $root: br }];
2206
2231
  const buildArgs = (beforeReturn) => (0, import_parameter.buildSwcParameterArgs)(inst, m.propertyKey, {
2232
+ ...common,
2207
2233
  eventObject: event2,
2208
2234
  matchedElement: matchedEl,
2209
- hostSet: hs,
2210
- helperHostSet: helperHostSetForMatch,
2211
- helperSet: helperSetForMatch,
2212
2235
  eventBeforeReturn: beforeReturn
2213
2236
  }, legacyArgs);
2214
2237
  let args = buildArgs(void 0);