@dooboostore/simple-web-component 1.0.53 → 1.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +308 -56
- package/dist/cjs/decorators/addEventListener.js +37 -14
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/applyAttribute.js +6 -3
- package/dist/cjs/decorators/applyAttribute.js.map +2 -2
- package/dist/cjs/decorators/applyClass.js +18 -2
- package/dist/cjs/decorators/applyClass.js.map +2 -2
- package/dist/cjs/decorators/applyNode.js +24 -2
- package/dist/cjs/decorators/applyNode.js.map +2 -2
- package/dist/cjs/decorators/changedAttribute.js +2 -5
- package/dist/cjs/decorators/changedAttribute.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +13 -2
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/eventMedia.js +2 -5
- package/dist/cjs/decorators/eventMedia.js.map +2 -2
- package/dist/cjs/decorators/fetch.js +216 -82
- package/dist/cjs/decorators/fetch.js.map +3 -3
- package/dist/cjs/decorators/index.js +1 -0
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/intersectionObserver.js +3 -6
- package/dist/cjs/decorators/intersectionObserver.js.map +2 -2
- package/dist/cjs/decorators/mutationObserver.js +3 -6
- package/dist/cjs/decorators/mutationObserver.js.map +2 -2
- package/dist/cjs/decorators/parameter.js +197 -33
- package/dist/cjs/decorators/parameter.js.map +3 -3
- package/dist/cjs/decorators/persistState.js +474 -0
- package/dist/cjs/decorators/persistState.js.map +7 -0
- package/dist/cjs/decorators/resizeObserver.js +3 -6
- package/dist/cjs/decorators/resizeObserver.js.map +2 -2
- package/dist/cjs/decorators/setInterval.js +2 -5
- package/dist/cjs/decorators/setInterval.js.map +2 -2
- package/dist/cjs/decorators/setTimeout.js +2 -5
- package/dist/cjs/decorators/setTimeout.js.map +2 -2
- package/dist/cjs/decorators/subscribeSwcAppMessage.js.map +1 -1
- package/dist/cjs/elements/SwcAppMixin.js +50 -2
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js +38 -15
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/applyAttribute.js +6 -3
- package/dist/esm/decorators/applyAttribute.js.map +2 -2
- package/dist/esm/decorators/applyClass.js +18 -2
- package/dist/esm/decorators/applyClass.js.map +2 -2
- package/dist/esm/decorators/applyNode.js +24 -2
- package/dist/esm/decorators/applyNode.js.map +2 -2
- package/dist/esm/decorators/changedAttribute.js +3 -6
- package/dist/esm/decorators/changedAttribute.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +15 -4
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/eventMedia.js +3 -6
- package/dist/esm/decorators/eventMedia.js.map +2 -2
- package/dist/esm/decorators/fetch.js +216 -82
- package/dist/esm/decorators/fetch.js.map +3 -3
- package/dist/esm/decorators/index.js +1 -0
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/intersectionObserver.js +4 -7
- package/dist/esm/decorators/intersectionObserver.js.map +2 -2
- package/dist/esm/decorators/mutationObserver.js +4 -7
- package/dist/esm/decorators/mutationObserver.js.map +2 -2
- package/dist/esm/decorators/parameter.js +197 -33
- package/dist/esm/decorators/parameter.js.map +3 -3
- package/dist/esm/decorators/persistState.js +455 -0
- package/dist/esm/decorators/persistState.js.map +7 -0
- package/dist/esm/decorators/resizeObserver.js +4 -7
- package/dist/esm/decorators/resizeObserver.js.map +2 -2
- package/dist/esm/decorators/setInterval.js +3 -6
- package/dist/esm/decorators/setInterval.js.map +2 -2
- package/dist/esm/decorators/setTimeout.js +3 -6
- package/dist/esm/decorators/setTimeout.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppMessage.js.map +1 -1
- package/dist/esm/elements/SwcAppMixin.js +51 -3
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +4470 -3620
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/addEventListener.d.ts +15 -0
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyAttribute.d.ts +1 -0
- package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
- package/dist/types/decorators/applyClass.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +14 -0
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/changedAttribute.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/eventMedia.d.ts.map +1 -1
- package/dist/types/decorators/fetch.d.ts +52 -31
- package/dist/types/decorators/fetch.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +1 -0
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/intersectionObserver.d.ts.map +1 -1
- package/dist/types/decorators/mutationObserver.d.ts.map +1 -1
- package/dist/types/decorators/parameter.d.ts +169 -31
- package/dist/types/decorators/parameter.d.ts.map +1 -1
- package/dist/types/decorators/persistState.d.ts +66 -0
- package/dist/types/decorators/persistState.d.ts.map +1 -0
- package/dist/types/decorators/resizeObserver.d.ts.map +1 -1
- package/dist/types/decorators/setInterval.d.ts.map +1 -1
- package/dist/types/decorators/setTimeout.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppMessage.d.ts +1 -1
- package/dist/types/decorators/subscribeSwcAppMessage.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts +12 -0
- package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +4470 -3620
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +1 -1
- package/src/decorators/addEventListener.ts +23 -15
- package/src/decorators/applyAttribute.ts +8 -3
- package/src/decorators/applyClass.ts +22 -2
- package/src/decorators/applyNode.ts +44 -2
- package/src/decorators/changedAttribute.ts +3 -4
- package/src/decorators/elementDefine.ts +19 -7
- package/src/decorators/eventMedia.ts +3 -6
- package/src/decorators/fetch.ts +270 -140
- package/src/decorators/index.ts +1 -0
- package/src/decorators/intersectionObserver.ts +4 -5
- package/src/decorators/mutationObserver.ts +4 -5
- package/src/decorators/parameter.ts +326 -42
- package/src/decorators/persistState.ts +408 -0
- package/src/decorators/resizeObserver.ts +4 -5
- package/src/decorators/setInterval.ts +3 -4
- package/src/decorators/setTimeout.ts +3 -4
- package/src/decorators/subscribeSwcAppMessage.ts +1 -1
- 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
|
|
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 `@
|
|
409
|
-
- **`before` hook results** — `@eventBeforeReturn`, `@routeChangeBeforeReturn`, `@
|
|
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,
|
|
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, @
|
|
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
|
|
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 → `@
|
|
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
|
-
-
|
|
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.
|
|
@@ -1999,8 +2038,8 @@ Late subscribers can receive past messages. The buffer keeps every typed message
|
|
|
1999
2038
|
```typescript
|
|
2000
2039
|
// 'behavior' = last message only, 'replay' = whole buffer in order.
|
|
2001
2040
|
// Unset (or 'subject') = live only.
|
|
2002
|
-
@subscribeSwcAppMessage('auth-changed', { subject: 'behavior' })
|
|
2003
|
-
onAuth(@
|
|
2041
|
+
@subscribeSwcAppMessageBehavior('auth-changed') // = @subscribeSwcAppMessage('auth-changed', { subject: 'behavior' })
|
|
2042
|
+
onAuth(@swcAppMessage msg: SwcAppMessage<User | null>) { ... }
|
|
2004
2043
|
```
|
|
2005
2044
|
|
|
2006
2045
|
`trigger` controls when replay happens (default `'connected'`).
|
|
@@ -2014,12 +2053,26 @@ onAuth(@appMessage msg: SwcAppMessage<User | null>) { ... }
|
|
|
2014
2053
|
```typescript
|
|
2015
2054
|
@subscribeSwcAppMessage('auth-changed', { subject: 'behavior', trigger: 'connectedDone' })
|
|
2016
2055
|
@innerHtml('.wrap')
|
|
2017
|
-
async load(@
|
|
2056
|
+
async load(@swcAppMessage msg: SwcAppMessage<User | null>) { ... }
|
|
2018
2057
|
```
|
|
2019
2058
|
|
|
2020
2059
|
Route subscribers (`@subscribeSwcAppRouteChange`) accept the same `trigger`.
|
|
2021
2060
|
Live broadcasts always reach everyone regardless of trigger.
|
|
2022
2061
|
|
|
2062
|
+
### `@swcAppMessage` on fields
|
|
2063
|
+
|
|
2064
|
+
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`:
|
|
2065
|
+
|
|
2066
|
+
```typescript
|
|
2067
|
+
@swcAppMessage last?: SwcAppMessage; // every type, live only
|
|
2068
|
+
@swcAppMessage('auth-changed') auth?: SwcAppMessage<User | null>; // live only (default 'subject')
|
|
2069
|
+
@swcAppMessage('auth-changed', { subject: 'behavior' }) me?: SwcAppMessage<User | null>; // late element: last one
|
|
2070
|
+
@swcAppMessage({ messageType: 'auth-changed', subject: 'replay' }) all?: SwcAppMessage; // late element: buffer in order
|
|
2071
|
+
```
|
|
2072
|
+
|
|
2073
|
+
- 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.
|
|
2074
|
+
- `@swcAppMessageBeforeReturn` stays parameter-only: it is the `before` hook's result for one handler call.
|
|
2075
|
+
|
|
2023
2076
|
## 🔌 App Host Hooks (onConnected / onSwcAppConnected / onDisconnected)
|
|
2024
2077
|
|
|
2025
2078
|
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 +2117,119 @@ Use `connectedElements()` to get the currently connected child elements.
|
|
|
2064
2117
|
|
|
2065
2118
|
## 🌐 @fetch — Declarative HTTP
|
|
2066
2119
|
|
|
2120
|
+
`@fetch` and its aliases (`@fetchGet`, `@fetchPost`, `@fetchLatest`, `@fetchManual`, …) go in one of three places.
|
|
2121
|
+
Pick by **who calls it** and **whether the result should be remembered**:
|
|
2122
|
+
|
|
2123
|
+
| Where | Declare | Use when | Remembers the result? |
|
|
2124
|
+
|---|---|---|---|
|
|
2125
|
+
| **Method** | `load(@fetchPromise p: Promise<T>) { … }` | the framework calls it — a trigger handler (`@eventClick`, `@onConnectedAfter`, a route…) | no |
|
|
2126
|
+
| **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 |
|
|
2127
|
+
| **Value field** | `declare me?: Promise<T>;` | data you load once and keep reading (`await this.me`) | **yes** — until you clear it |
|
|
2128
|
+
|
|
2129
|
+
### 1. On a method — trigger handlers
|
|
2130
|
+
|
|
2131
|
+
Stack the trigger, the outputs and `@fetch` on one method. The request starts first; its `Promise` is handed to the
|
|
2132
|
+
`@fetchPromise` parameter and the method runs **right away**. The method's own return value is returned unchanged, so the
|
|
2133
|
+
signature you wrote stays true (a sync method stays sync).
|
|
2134
|
+
|
|
2067
2135
|
```typescript
|
|
2068
|
-
|
|
2069
|
-
@
|
|
2070
|
-
|
|
2071
|
-
|
|
2136
|
+
@eventClick('.load')
|
|
2137
|
+
@innerHtml('.out', { fallback: () => 'Loading…' }) // shown until the returned Promise settles
|
|
2138
|
+
@fetchLatest('/api/post/1') // click again → the previous request is aborted
|
|
2139
|
+
load(@fetchPromise p: Promise<Post>) {
|
|
2140
|
+
return p.then(post => post.title, () => 'Failed'); // success / failure, no try/catch
|
|
2072
2141
|
}
|
|
2142
|
+
```
|
|
2073
2143
|
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
@fetch({ url: '/api/post/1', request: 'GET' })
|
|
2077
|
-
async loadBefore(@fetchSettled settled: PromiseSettledResult<any>) {
|
|
2078
|
-
return settled.status === 'fulfilled' ? settled.value : null;
|
|
2079
|
-
}
|
|
2144
|
+
If you also call such a method yourself, declare the parameter optional (`@fetchPromise p?: Promise<T>`) — the
|
|
2145
|
+
framework fills it, callers don't. For a request you call yourself, a field (below) is the better fit.
|
|
2080
2146
|
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2147
|
+
### 2. Function field — a request function you call
|
|
2148
|
+
|
|
2149
|
+
The framework writes the function body; the declared type is the real signature (no injected parameter, no changed
|
|
2150
|
+
return type).
|
|
2151
|
+
|
|
2152
|
+
```typescript
|
|
2153
|
+
// GET / DELETE: the arguments feed url / request
|
|
2154
|
+
@fetchGet((_self, _helper, [id]) => `/api/posts/${id}`)
|
|
2155
|
+
declare getPost: (id: number) => Promise<Post>;
|
|
2086
2156
|
|
|
2087
|
-
//
|
|
2088
|
-
@
|
|
2089
|
-
|
|
2090
|
-
|
|
2157
|
+
// POST / PUT / PATCH: the last argument is the body
|
|
2158
|
+
@fetchPost('/api/posts', { process: 'json' })
|
|
2159
|
+
declare createPost: (body: NewPost) => Promise<Post>;
|
|
2160
|
+
|
|
2161
|
+
@fetchLatest({ url: (_s, _h, [q]) => `/api/search?q=${q}` }) // only the latest call settles
|
|
2162
|
+
declare search: (q: string) => Promise<Item[]>;
|
|
2163
|
+
|
|
2164
|
+
// use it from a trigger handler (or anywhere)
|
|
2165
|
+
@eventClick('.load')
|
|
2166
|
+
@innerHtml('.out', { fallback: () => 'Loading…' })
|
|
2167
|
+
show() {
|
|
2168
|
+
return this.getPost(1).then(p => p.title);
|
|
2091
2169
|
}
|
|
2092
2170
|
```
|
|
2093
2171
|
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2172
|
+
Every call is a new request. Success resolves, failure rejects with `HttpResponseError` (see below).
|
|
2173
|
+
|
|
2174
|
+
### 3. Value field — data that is remembered
|
|
2175
|
+
|
|
2176
|
+
```typescript
|
|
2177
|
+
@fetch('/api/me')
|
|
2178
|
+
declare me?: Promise<User>; // `?` so that `this.me = undefined` type-checks under `strict`
|
|
2179
|
+
|
|
2180
|
+
await this.me; // first read: request → remembered on success
|
|
2181
|
+
await this.me; // remembered result (no request)
|
|
2182
|
+
|
|
2183
|
+
this.me = undefined; // forget it (null works too) …
|
|
2184
|
+
await this.me; // … so this read requests again — this is how you reload
|
|
2185
|
+
|
|
2186
|
+
this.me = savedUser; // or seed a value yourself (e.g. data that came with SSR) — no request
|
|
2187
|
+
```
|
|
2188
|
+
|
|
2189
|
+
- Declare it optional (`declare me?: Promise<T>`) if you ever clear it: under `strict`, assigning `undefined` to a
|
|
2190
|
+
plain `Promise<T>` is a type error. Reading it is still `await this.me` (the result type is `T | undefined`).
|
|
2191
|
+
If you never clear it, `declare me: Promise<T>` is fine.
|
|
2192
|
+
- Clear it by assigning, not with `delete this.me` — the memory lives behind the field's setter.
|
|
2193
|
+
|
|
2194
|
+
- **Remembered**: success, per element. **Not remembered**: failure — the next read requests again.
|
|
2195
|
+
- **Forgotten**: when you assign `undefined` / `null`, and when the element disconnects (the request is aborted; a read
|
|
2196
|
+
after reconnecting requests again).
|
|
2197
|
+
- There are no arguments — build the body in the `request` factory if the request needs one.
|
|
2198
|
+
- If the data must be fresh on every use, declare a function field instead (`declare loadMe: () => Promise<User>`).
|
|
2199
|
+
- The value is a real Promise to your code (`instanceof Promise` is true), so it can be returned straight to an output
|
|
2200
|
+
decorator: `@innerHtml('.name') showName() { return this.me.then(u => u.name); }`.
|
|
2201
|
+
|
|
2202
|
+
### Field rules (function and value fields)
|
|
2203
|
+
|
|
2204
|
+
- **Always write `declare`.** Without it, builds with `useDefineForClassFields: true` (the default for target ES2022+)
|
|
2205
|
+
create an instance field that hides what the framework put there:
|
|
2206
|
+
|
|
2207
|
+
| Build setting | `declare me: Promise<T>` | `me!: Promise<T>` (no `declare`) |
|
|
2208
|
+
|---|---|---|
|
|
2209
|
+
| `useDefineForClassFields: false` | works | works (but `strict` needs the `!`) |
|
|
2210
|
+
| `useDefineForClassFields: true` / ES2022+ default | works | **broken** — reported on connect: *must be declared with `declare`* |
|
|
2211
|
+
|
|
2212
|
+
- **Declared type is checked.** At compile time the field must be `(...args) => Promise<T>` or `Promise<T>`
|
|
2213
|
+
(`string`, `() => T`, … are errors; optional `?` fields are fine; `private` / `protected` fields can't be seen by
|
|
2214
|
+
TypeScript and are not checked).
|
|
2215
|
+
Builds that emit `design:type` (`emitDecoratorMetadata` with tsc / ts-loader) also reject a non-function, non-Promise
|
|
2216
|
+
type at runtime.
|
|
2217
|
+
- **Nothing else on the field.** Triggers and outputs go on a method that calls the field. Method decorators on a field
|
|
2218
|
+
are already compile errors; any other SWC decorator on the same field (`@attribute`, `@query`, …, or anything via
|
|
2219
|
+
`as any`) throws when the class is defined.
|
|
2220
|
+
- **Same in every build.** Function vs. value is decided by how you declared it, not by build metadata: the field holds
|
|
2221
|
+
one object that is callable and a Promise, and TypeScript lets you use it only the way you declared it.
|
|
2222
|
+
- **Quiet ends.** A call skipped by `filter` or made while the element is detached, and a call aborted by the framework
|
|
2223
|
+
(disconnect, `abortPrevious`), return a Promise that **never settles** — nothing draws on a detached DOM, nothing throws.
|
|
2224
|
+
|
|
2225
|
+
### Method modes
|
|
2226
|
+
|
|
2227
|
+
- **before** (default, or `trigger: 'before'`): start the request → inject its `Promise` via
|
|
2228
|
+
`@fetchPromise` → run the method **right away**. Returns the method's own return value, so the
|
|
2229
|
+
signature you wrote stays true (sync stays sync). Success resolves, failure rejects — handle both with
|
|
2230
|
+
`then` / `catch` / `finally` on the Promise.
|
|
2231
|
+
If you also call the method yourself, declare the parameter optional (`@fetchPromise p?: Promise<T>`) —
|
|
2232
|
+
the framework fills it, callers don't.
|
|
2098
2233
|
- **after** (`trigger: 'after'`, or just `valueKey`): run the method → its return value
|
|
2099
2234
|
(or `returnValue[valueKey]`) becomes the body → fetch. Returns the fetch result; a failed fetch throws.
|
|
2100
2235
|
`valueKey` is after-only — combining it with `trigger: 'before'` is a type error.
|
|
@@ -2107,7 +2242,7 @@ async saveForm() {
|
|
|
2107
2242
|
```typescript
|
|
2108
2243
|
// service call — only the result matters
|
|
2109
2244
|
@fetch({ manual: (self) => self.myService.getProfile({}) })
|
|
2110
|
-
|
|
2245
|
+
load(@fetchPromise p: Promise<MyService.ProfileResponse>) { ... }
|
|
2111
2246
|
|
|
2112
2247
|
// your own fetch — pass the signal so an abort cancels the network request too
|
|
2113
2248
|
@fetch({ trigger: 'after', manual: (_self, _helper, _params, signal, returnValue) =>
|
|
@@ -2136,38 +2271,37 @@ Its return value is the fetch result.
|
|
|
2136
2271
|
|
|
2137
2272
|
```typescript
|
|
2138
2273
|
@fetch('/api/post/1')
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
return settled.reason.response?.status; // e.g. 404
|
|
2142
|
-
}
|
|
2274
|
+
load(@fetchPromise p: Promise<Post>) {
|
|
2275
|
+
return p.catch(e => isHttpResponseError(e) ? e.response?.status : undefined); // e.g. 404
|
|
2143
2276
|
}
|
|
2144
2277
|
```
|
|
2145
2278
|
|
|
2146
|
-
**
|
|
2147
|
-
- `filter(
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
-
|
|
2151
|
-
`
|
|
2279
|
+
**filter** — the only hook
|
|
2280
|
+
- `filter({ self, helper, args })` → `false` skips the whole call: no request, no method. A method returns `undefined`;
|
|
2281
|
+
a field returns a Promise that never settles.
|
|
2282
|
+
It is synchronous: the request starts before the method runs, so "send or not" can only be decided here.
|
|
2283
|
+
- There is no `before` / `after` / `finally` on `@fetch`: result handling is plain Promise code
|
|
2284
|
+
(`then` / `catch` / `finally`), and gating or cleanup around the call lives on the trigger you stack it with
|
|
2285
|
+
(`@eventClick`, `@onConnectedAfter`, …), which already has `filter → before → handler → finally`.
|
|
2152
2286
|
|
|
2153
2287
|
**Cancellation**
|
|
2154
2288
|
- Every call gets its own `AbortController`. Declarative requests get its signal as `init.signal`
|
|
2155
2289
|
(merged with a `signal` you return from `request`, via `AbortSignal.any` or a fallback); `manual` gets it as
|
|
2156
2290
|
the `signal` argument.
|
|
2157
|
-
- When the element disconnects, all its in-flight `@fetch` requests are aborted.
|
|
2158
|
-
|
|
2159
|
-
|
|
2291
|
+
- When the element disconnects, all its in-flight `@fetch` requests are aborted. The injected Promise then
|
|
2292
|
+
**never settles** (before mode), so nothing draws on a detached DOM and nothing throws; an after-mode call
|
|
2293
|
+
ends quietly with `undefined`.
|
|
2160
2294
|
- A call that *starts* while the element is detached (e.g. a `setTimeout` scheduled just before the user
|
|
2161
2295
|
navigated away) is skipped the same quiet way. Elements that were never connected are not affected.
|
|
2162
2296
|
- `manual` should pass `signal` on to its own client (`fetch`, axios, ...) so the network
|
|
2163
2297
|
request is actually cancelled. If it ignores the signal, the call still ends as soon as it's aborted
|
|
2164
2298
|
(the result is raced against the abort) — the request just keeps running in the background and its
|
|
2165
2299
|
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
|
|
2300
|
+
- `abortPrevious: true` aborts the previous in-flight call of the same method (per element) when it's called again
|
|
2301
|
+
(search-as-you-type) — the superseded Promise never settles, so a late old response can't
|
|
2168
2302
|
overwrite the newest result.
|
|
2169
|
-
- Aborting through your own signal is not quiet: it
|
|
2170
|
-
or
|
|
2303
|
+
- Aborting through your own signal is not quiet: it rejects the Promise (before mode)
|
|
2304
|
+
or throws (after mode), like any other failure.
|
|
2171
2305
|
|
|
2172
2306
|
**Aliases**
|
|
2173
2307
|
|
|
@@ -2183,13 +2317,13 @@ For the method aliases, `request` may only be a factory returning `RequestInit`
|
|
|
2183
2317
|
|
|
2184
2318
|
```typescript
|
|
2185
2319
|
@fetchManual((self) => self.myService.getProfile({}))
|
|
2186
|
-
|
|
2320
|
+
load(@fetchPromise p: Promise<Profile>) { ... }
|
|
2187
2321
|
|
|
2188
2322
|
@fetchPost('/api/posts', { process: 'json' })
|
|
2189
2323
|
async save() { return { title: 'hi' }; }
|
|
2190
2324
|
|
|
2191
2325
|
@fetchDelete((_self, _helper, params) => `/api/posts/${params[0]}`)
|
|
2192
|
-
|
|
2326
|
+
remove(id: number, @fetchPromise p?: Promise<unknown>) { ... }
|
|
2193
2327
|
```
|
|
2194
2328
|
|
|
2195
2329
|
**Composition** — e.g. form submit:
|
|
@@ -2197,6 +2331,124 @@ async remove(id: number, @fetchSettled settled?: PromiseSettledResult<unknown>)
|
|
|
2197
2331
|
stacked on `@fetch({ url: '/api/echo', trigger: 'after', process: 'form' })`, with the method taking
|
|
2198
2332
|
`@eventBeforeReturn formData: FormData` and returning it.
|
|
2199
2333
|
|
|
2334
|
+
## 🧩 Value-Injecting Parameter Decorators (@querySelectorParam, @attributeParam, @local/session/cookie/indexedDbParam, @fetchParam, @swcAppRouter)
|
|
2335
|
+
|
|
2336
|
+
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.
|
|
2337
|
+
|
|
2338
|
+
> 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.
|
|
2339
|
+
|
|
2340
|
+
### @querySelectorParam / @querySelectorAllParam
|
|
2341
|
+
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.
|
|
2342
|
+
|
|
2343
|
+
```typescript
|
|
2344
|
+
@onConnectedAfter
|
|
2345
|
+
onReady(
|
|
2346
|
+
@querySelectorParam('#name') input: HTMLInputElement,
|
|
2347
|
+
@querySelectorAllParam('.item', { root: 'all' }) items: HTMLElement[]
|
|
2348
|
+
) {
|
|
2349
|
+
input.focus();
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
@addEventListener('#save', 'click')
|
|
2353
|
+
onSave(@querySelectorShadowParam('.form') form: HTMLFormElement) { ... }
|
|
2354
|
+
```
|
|
2355
|
+
- Root/pick shorthands mirror `@query`'s own family: `querySelectorShadowParam` / `querySelectorLightParam` / `querySelectorAllRootsParam` (single), `querySelectorAllShadowParam` / `querySelectorAllLightParam` / `querySelectorAllAllParam` (arrays).
|
|
2356
|
+
|
|
2357
|
+
### @attributeParam
|
|
2358
|
+
Same engine as the field/method `@attribute`.
|
|
2359
|
+
|
|
2360
|
+
```typescript
|
|
2361
|
+
onReady(
|
|
2362
|
+
@attributeParam('data-x') ownAttr: string,
|
|
2363
|
+
@attributeParam('#child', 'data-y', { root: 'shadow' }) childAttr: string
|
|
2364
|
+
) { ... }
|
|
2365
|
+
```
|
|
2366
|
+
- One string = this element's own attribute; `(selector, name, options?)` = another element's attribute (same two-form shape as the field decorator).
|
|
2367
|
+
- `options.type` converts to `Number`/`Boolean`, same as the field decorator; missing attribute/target → `null`.
|
|
2368
|
+
|
|
2369
|
+
### @localStorageParam / @sessionStorageParam / @cookieParam / @indexedDbParam
|
|
2370
|
+
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:
|
|
2371
|
+
|
|
2372
|
+
```typescript
|
|
2373
|
+
onReady(
|
|
2374
|
+
@localStorageParam('theme') theme: string,
|
|
2375
|
+
@indexedDbParam('draft') draftPromise: Promise<string>
|
|
2376
|
+
) {
|
|
2377
|
+
this.applyTheme(theme);
|
|
2378
|
+
draftPromise.then(d => this.restoreDraft(d));
|
|
2379
|
+
}
|
|
2380
|
+
```
|
|
2381
|
+
|
|
2382
|
+
### @fetchParam
|
|
2383
|
+
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.
|
|
2384
|
+
|
|
2385
|
+
```typescript
|
|
2386
|
+
@onConnectedAfter
|
|
2387
|
+
async onReady(@fetchParam('/api/products/1') p: Promise<Product>) {
|
|
2388
|
+
this.product = await p;
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
// url/init accept (currentThis, helper) => ... callbacks too, same shape as @fetch's factories —
|
|
2392
|
+
// handy for referencing instance fields to build a dynamic URL or body.
|
|
2393
|
+
@addEventListener('#save', 'click')
|
|
2394
|
+
async onSave(@fetchParam(
|
|
2395
|
+
(self) => `/api/products/${self.productId}`,
|
|
2396
|
+
(self) => ({ method: 'POST', body: JSON.stringify({ qty: self.qty }) })
|
|
2397
|
+
) p: Promise<any>) {
|
|
2398
|
+
await p;
|
|
2399
|
+
}
|
|
2400
|
+
```
|
|
2401
|
+
|
|
2402
|
+
### @swcAppRouter / @swcAppSimpleApplication / @swcAppHost
|
|
2403
|
+
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.
|
|
2404
|
+
|
|
2405
|
+
## 💾 Persisted State (@localStorage, @sessionStorage, @cookie, @indexedDb, @persistState)
|
|
2406
|
+
|
|
2407
|
+
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).
|
|
2408
|
+
|
|
2409
|
+
```typescript
|
|
2410
|
+
class Settings extends HTMLElement {
|
|
2411
|
+
// Field — bare key defaults to the field name; the stored value wins over the initializer on reconnect
|
|
2412
|
+
@localStorage theme: string = 'dark';
|
|
2413
|
+
|
|
2414
|
+
// Explicit key
|
|
2415
|
+
@sessionStorage('draft-id') draftId?: string;
|
|
2416
|
+
|
|
2417
|
+
@cookie('session-token', { maxAge: 3600, sameSite: 'Strict' })
|
|
2418
|
+
token?: string;
|
|
2419
|
+
|
|
2420
|
+
// Method — persists the return value (JSON-serialized) each time it runs
|
|
2421
|
+
@localStorage('last-search')
|
|
2422
|
+
search(q: string) { return q; }
|
|
2423
|
+
}
|
|
2424
|
+
```
|
|
2425
|
+
|
|
2426
|
+
- **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).
|
|
2427
|
+
- **Method**: the return value is persisted after the method runs (`valueKey` picks one field out of an object return).
|
|
2428
|
+
- Backends: `local` / `session` / `cookie` (sync) and `indexeddb` (async). The generic form is `@persistState(key?, { storage, ... })`; `@localStorage`/`@sessionStorage`/`@cookie`/`@indexedDb` are storage-fixed aliases.
|
|
2429
|
+
- `@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.
|
|
2430
|
+
- Options: `valueKey`, `serialize`/`deserialize` (default `JSON.stringify`/`JSON.parse`); `cookie` also takes `path`/`domain`/`maxAge`/`expires`/`secure`/`sameSite`.
|
|
2431
|
+
|
|
2432
|
+
**Removing a key**
|
|
2433
|
+
```typescript
|
|
2434
|
+
class Settings extends HTMLElement {
|
|
2435
|
+
@localStorage theme: string = 'dark';
|
|
2436
|
+
|
|
2437
|
+
@removeLocalStorage('theme')
|
|
2438
|
+
clearTheme() {}
|
|
2439
|
+
}
|
|
2440
|
+
```
|
|
2441
|
+
- `@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.
|
|
2442
|
+
- Generic form: `@removePersistState(key?, options?)`.
|
|
2443
|
+
|
|
2444
|
+
**Direct function access** (no decorator needed) — for a plain method body, or the async backend:
|
|
2445
|
+
```typescript
|
|
2446
|
+
import { persistRead, persistWrite, persistRemove, persistReadAsync, persistWriteAsync, persistRemoveAsync } from '@dooboostore/simple-web-component';
|
|
2447
|
+
|
|
2448
|
+
const cached = persistRead(this, 'theme', { storage: 'local' });
|
|
2449
|
+
const draft = await persistReadAsync(this, 'draft', { storage: 'indexeddb' });
|
|
2450
|
+
```
|
|
2451
|
+
|
|
2200
2452
|
## 💧 @property Hydration Rules
|
|
2201
2453
|
|
|
2202
2454
|
- 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
|
|
2058
|
-
const legacyArgs = [event2, { currentHostSet, $matchedElement: matchedElement }, { event: event2, ...
|
|
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
|
|
2203
|
-
const legacyArgs = [event2, { ...
|
|
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);
|