@supersoniks/concorde 4.7.4 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +1 -1
  2. package/ai/cursor/rules/concorde.mdc +1 -1
  3. package/ai/skills/concorde-scope/SKILL.md +2 -2
  4. package/build-infos.json +1 -1
  5. package/concorde-core.bundle.js +289 -289
  6. package/concorde-core.es.js +4837 -4544
  7. package/dist/concorde-core.bundle.js +289 -289
  8. package/dist/concorde-core.es.js +4837 -4544
  9. package/dist/docs-mock-api-sw.js +19 -0
  10. package/dist/docs-mock-api-sw.js.map +2 -2
  11. package/docs/assets/index-wyNMyWT9.js +11196 -0
  12. package/docs/docs-mock-api-sw.js +19 -0
  13. package/docs/docs-mock-api-sw.js.map +2 -2
  14. package/docs/index.html +1 -1
  15. package/package.json +9 -1
  16. package/public/docs-mock-api-sw.js +19 -0
  17. package/public/docs-mock-api-sw.js.map +2 -2
  18. package/src/core/components/functional/example/example.ts +3 -3
  19. package/src/core/components/ui/icon/icon.ts +17 -2
  20. package/src/core/components/ui/menu/menu.ts +12 -3
  21. package/src/core/decorators/api.post.spec.ts +293 -0
  22. package/src/core/decorators/api.spec.ts +6 -6
  23. package/src/core/decorators/api.ts +643 -12
  24. package/src/core/decorators/subscriber/bind.ts +13 -5
  25. package/src/core/decorators/subscriber/dynamicPath.spec.ts +53 -0
  26. package/src/core/decorators/subscriber/dynamicPath.ts +23 -1
  27. package/src/core/decorators/subscriber/handle.ts +3 -1
  28. package/src/core/decorators/subscriber/onAssign.ts +10 -2
  29. package/src/core/decorators/subscriber/publish.ts +12 -2
  30. package/src/core/utils/PublisherProxy.ts +95 -11
  31. package/src/core/utils/api.ts +72 -3
  32. package/src/core/utils/dpOptions.spec.ts +56 -0
  33. package/src/core/utils/endpoint.ts +3 -3
  34. package/src/decorators.ts +17 -1
  35. package/src/docs/_core-concept/dataFlow.md +9 -3
  36. package/src/docs/_decorators/bind.md +2 -2
  37. package/src/docs/_decorators/get.md +13 -4
  38. package/src/docs/_decorators/handle.md +5 -1
  39. package/src/docs/_decorators/on-assign.md +2 -0
  40. package/src/docs/_decorators/patch.md +45 -0
  41. package/src/docs/_decorators/post.md +93 -0
  42. package/src/docs/_decorators/publish.md +1 -1
  43. package/src/docs/_decorators/put.md +43 -0
  44. package/src/docs/_decorators/subscribe.md +4 -1
  45. package/src/docs/_directives/sub.md +1 -1
  46. package/src/docs/_getting-started/my-first-component.md +1 -1
  47. package/src/docs/_misc/api-configuration.md +3 -1
  48. package/src/docs/_misc/dataProviderKey.md +2 -2
  49. package/src/docs/_misc/dynamic-path.md +71 -0
  50. package/src/docs/_misc/endpoint.md +5 -3
  51. package/src/docs/components/docs-demo-sources.ts +102 -3
  52. package/src/docs/components/docs-lit-demo-raw.ts +2 -26
  53. package/src/docs/components/docs-lit-demo.ts +9 -42
  54. package/src/docs/components/docs-source-excerpt.ts +53 -0
  55. package/src/docs/components/docs-source-link.ts +24 -8
  56. package/src/docs/components/docs-source-raw.ts +34 -0
  57. package/src/docs/example/decorators-demo-geo.ts +2 -2
  58. package/src/docs/example/decorators-demo-post.ts +249 -0
  59. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +5 -5
  60. package/src/docs/example/decorators-demo.ts +1 -0
  61. package/src/docs/example/docs-api-config-demos.ts +5 -5
  62. package/src/docs/mock-api/router.ts +20 -0
  63. package/src/docs/navigation/navigation.ts +16 -0
  64. package/src/docs/search/docs-search.json +540 -15
  65. package/src/tsconfig.json +24 -0
  66. package/src/tsconfig.tsbuildinfo +1 -1
  67. package/vite.config.mts +1 -1
  68. package/docs/assets/index-CwtPzTFq.js +0 -7508
  69. package/docs/src/core/components/functional/date/date.md +0 -290
  70. package/docs/src/core/components/functional/fetch/fetch.md +0 -125
  71. package/docs/src/core/components/functional/if/if.md +0 -9
  72. package/docs/src/core/components/functional/list/list.md +0 -65
  73. package/docs/src/core/components/functional/mix/mix.md +0 -41
  74. package/docs/src/core/components/functional/queue/queue.md +0 -72
  75. package/docs/src/core/components/functional/router/router.md +0 -94
  76. package/docs/src/core/components/functional/sdui/default-library.json +0 -108
  77. package/docs/src/core/components/functional/sdui/example.json +0 -99
  78. package/docs/src/core/components/functional/sdui/sdui.md +0 -356
  79. package/docs/src/core/components/functional/states/states.md +0 -87
  80. package/docs/src/core/components/functional/submit/submit.md +0 -114
  81. package/docs/src/core/components/functional/subscriber/subscriber.md +0 -91
  82. package/docs/src/core/components/functional/value/value.md +0 -35
  83. package/docs/src/core/components/ui/alert/alert.md +0 -121
  84. package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -0
  85. package/docs/src/core/components/ui/badge/badge.md +0 -127
  86. package/docs/src/core/components/ui/button/button.md +0 -182
  87. package/docs/src/core/components/ui/captcha/captcha.md +0 -12
  88. package/docs/src/core/components/ui/card/card.md +0 -97
  89. package/docs/src/core/components/ui/divider/divider.md +0 -35
  90. package/docs/src/core/components/ui/form/checkbox/checkbox.md +0 -77
  91. package/docs/src/core/components/ui/form/fieldset/fieldset.md +0 -129
  92. package/docs/src/core/components/ui/form/form-actions/form-actions.md +0 -77
  93. package/docs/src/core/components/ui/form/form-layout/form-layout.md +0 -44
  94. package/docs/src/core/components/ui/form/input/input.md +0 -142
  95. package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -133
  96. package/docs/src/core/components/ui/form/radio/radio.md +0 -57
  97. package/docs/src/core/components/ui/form/select/select.md +0 -71
  98. package/docs/src/core/components/ui/form/switch/switch.md +0 -57
  99. package/docs/src/core/components/ui/form/textarea/textarea.md +0 -65
  100. package/docs/src/core/components/ui/group/group.md +0 -75
  101. package/docs/src/core/components/ui/icon/icon.md +0 -125
  102. package/docs/src/core/components/ui/icon/icons.json +0 -1
  103. package/docs/src/core/components/ui/image/image.md +0 -107
  104. package/docs/src/core/components/ui/link/link.md +0 -43
  105. package/docs/src/core/components/ui/loader/loader.md +0 -55
  106. package/docs/src/core/components/ui/menu/menu.md +0 -329
  107. package/docs/src/core/components/ui/modal/modal.md +0 -119
  108. package/docs/src/core/components/ui/pop/pop.md +0 -96
  109. package/docs/src/core/components/ui/progress/progress.md +0 -63
  110. package/docs/src/core/components/ui/table/table.md +0 -455
  111. package/docs/src/core/components/ui/toast/toast.md +0 -166
  112. package/docs/src/core/components/ui/tooltip/tooltip.md +0 -82
  113. package/docs/src/docs/_core-concept/dataFlow.md +0 -73
  114. package/docs/src/docs/_core-concept/overview.md +0 -57
  115. package/docs/src/docs/_core-concept/subscriber.md +0 -75
  116. package/docs/src/docs/_decorators/ancestor-attribute.md +0 -79
  117. package/docs/src/docs/_decorators/auto-subscribe.md +0 -202
  118. package/docs/src/docs/_decorators/bind.md +0 -167
  119. package/docs/src/docs/_decorators/get.md +0 -68
  120. package/docs/src/docs/_decorators/handle.md +0 -171
  121. package/docs/src/docs/_decorators/on-assign.md +0 -388
  122. package/docs/src/docs/_decorators/publish.md +0 -55
  123. package/docs/src/docs/_decorators/subscribe.md +0 -97
  124. package/docs/src/docs/_decorators/wait-for-ancestors.md +0 -163
  125. package/docs/src/docs/_directives/sub.md +0 -91
  126. package/docs/src/docs/_getting-started/ai-agents.md +0 -56
  127. package/docs/src/docs/_getting-started/concorde-manual-install.md +0 -133
  128. package/docs/src/docs/_getting-started/concorde-outside.md +0 -33
  129. package/docs/src/docs/_getting-started/create-a-component.md +0 -139
  130. package/docs/src/docs/_getting-started/my-first-component.md +0 -236
  131. package/docs/src/docs/_getting-started/my-first-subscriber.md +0 -120
  132. package/docs/src/docs/_getting-started/pubsub.md +0 -37
  133. package/docs/src/docs/_getting-started/start.md +0 -47
  134. package/docs/src/docs/_getting-started/theming.md +0 -91
  135. package/docs/src/docs/_misc/api-configuration.md +0 -79
  136. package/docs/src/docs/_misc/dataProviderKey.md +0 -168
  137. package/docs/src/docs/_misc/docs-mock-api.md +0 -60
  138. package/docs/src/docs/_misc/endpoint.md +0 -43
  139. package/docs/src/docs/_misc/html-integration.md +0 -13
  140. package/docs/src/docs/search/docs-search.json +0 -8532
  141. package/docs/src/tag-list.json +0 -1
  142. package/docs/src/tsconfig-model.json +0 -23
  143. package/docs/src/tsconfig.json +0 -1095
@@ -1,167 +0,0 @@
1
- # @bind
2
-
3
- Binds a class property to a path in a publisher. The property updates when publisher data changes.
4
-
5
- For Lit re-renders, also add `@state()` on the same property.
6
-
7
- **See also:** [@subscribe](#docs/_decorators/subscribe.md/subscribe), [@handle](#docs/_decorators/handle.md/handle), [@publish](#docs/_decorators/publish.md/publish), [@get](#docs/_decorators/get.md/get).
8
-
9
- ## Principle
10
-
11
- The decorator subscribes to the DataProvider store using dot notation or a `DataProviderKey`. Updates flow into the decorated property ([Data flow](#docs/_core-concept/dataFlow.md/dataFlow)).
12
-
13
- ## Import
14
-
15
- <sonic-code language="typescript">
16
- <template>
17
- import { bind } from "@supersoniks/concorde/decorators";
18
- </template>
19
- </sonic-code>
20
-
21
- ## Example
22
-
23
- <sonic-code language="typescript">
24
- <template>
25
- @customElement("demo-bind")
26
- export class DemoBind extends LitElement {
27
- static styles = [tailwind];
28
-
29
- @bind("demoData.firstName")
30
- @state()
31
- firstName = "";
32
-
33
- @bind("demoData.lastName")
34
- @state()
35
- lastName: string = "";
36
-
37
- @bind("demoData.count")
38
- @state()
39
- count: number = 0;
40
-
41
- render() {
42
- return //......
43
- }
44
-
45
- updateData() {
46
- set(demoDataKey, { ...get(demoDataKey), count: get(demoDataKey).count + 1 });
47
- // see demo-bind in src/docs/example/decorators-demo-bind-demos.ts
48
- const randomIndex = Math.floor(Math.random() * demoUsers.get().length);
49
- const randomUser = demoUsers.get()[randomIndex];
50
- demoData.set({
51
- firstName: randomUser.firstName,
52
- lastName: randomUser.lastName,
53
- count: (demoData.count.get() || 0) + 1,
54
- });
55
- }
56
- }
57
-
58
- </template>
59
- </sonic-code>
60
-
61
- <sonic-code>
62
- <template>
63
- <docs-demo-sources for="demo-bind"></docs-demo-sources>
64
- <demo-bind></demo-bind>
65
- </template>
66
- </sonic-code>
67
-
68
- ## `DataProviderKey` (strict typing)
69
-
70
- `@bind` accepts either a string path (legacy) or a `DataProviderKey<T>`. The property type must match `T`. Use `reflect: true` to push local writes back to the publisher (see below). See [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey).
71
-
72
- <sonic-code language="typescript">
73
- <template>
74
- import { bind } from "@supersoniks/concorde/decorators";
75
- import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
76
-
77
- type Data = { count: number };
78
- const dataKey = new DataProviderKey<Data>("data");
79
-
80
- @bind(dataKey.count, { reflect: true })
81
- @state()
82
- count: number = 0;
83
- </template>
84
- </sonic-code>
85
-
86
- ## Reflect (`reflect: true`)
87
-
88
- Two-way sync: reads from the publisher and local assignments call `publisher.set(...)`. An internal guard avoids infinite loops.
89
-
90
- <sonic-code language="typescript">
91
- <template>
92
- @bind("userData.profile.avatarUrl", { reflect: true })
93
- @state()
94
- avatar: string;
95
- </template>
96
- </sonic-code>
97
-
98
- <sonic-code language="typescript">
99
- <template>
100
- @customElement("demo-bind-reflect")
101
- export class DemoBindReflect extends LitElement {
102
- static styles = [tailwind];
103
-
104
- @bind("bindReflectDemo.count", { reflect: true })
105
- @state()
106
- withReflect: number = 0;
107
-
108
- @bind("bindReflectDemo.count")
109
- @state()
110
- withoutReflect: number = 0;
111
-
112
- render() {
113
- return html`
114
- <div class="mb-3">
115
- from publisher : ${sub("bindReflectDemo.count") || 0} <br />
116
- from component with reflect : ${this.withReflect || 0} <br />
117
- from component without reflect : ${this.withoutReflect || 0}
118
- </div>
119
- <sonic-button @click=${() => this.withReflect++}
120
- >Increment with reflect</sonic-button
121
- >
122
- <sonic-button @click=${() => this.withoutReflect++}
123
- >Increment without reflect</sonic-button
124
- >
125
- `;
126
- }
127
- }
128
-
129
- </template>
130
- </sonic-code>
131
-
132
- <sonic-code toggleCode>
133
- <template>
134
- <docs-demo-sources for="demo-bind-reflect"></docs-demo-sources>
135
- <demo-bind-reflect></demo-bind-reflect>
136
- </template>
137
- </sonic-code>
138
-
139
- ## Path syntax
140
-
141
- - First segment: data provider id.
142
- - Nested properties: dot notation.
143
- - Arrays: numeric index (`items.0`).
144
-
145
- ### Dynamic paths
146
-
147
- Use `${prop}` or `${this.prop}` inside a **normal string literal** (not a JS template literal with backticks). `@bind` re-subscribes when a reactive dependency changes.
148
-
149
- > Properties referenced in the pattern must be reactive (`@property`, etc.) or you must call `requestUpdate` manually.
150
-
151
- <sonic-code>
152
- <template>
153
- <docs-demo-sources for="demo-bind-dynamic"></docs-demo-sources>
154
- <demo-bind-dynamic></demo-bind-dynamic>
155
- </template>
156
- </sonic-code>
157
-
158
- ## Behavior
159
-
160
- - Subscribes at `connectedCallback`, unsubscribes at `disconnectedCallback`.
161
- - If the path does not exist yet, a publisher may be created with `null`.
162
-
163
- ## Notes
164
-
165
- Works with any component that has the usual DOM lifecycle (`LitElement`, `Subscriber` mixin, etc.).
166
-
167
- Shared data: [Sharing data](#docs/_getting-started/pubsub.md/pubsub).
@@ -1,68 +0,0 @@
1
- # @get
2
-
3
- Loads data through [`API.getDetailed`](../../core/utils/api.ts). The decorated property is **`ApiGetResult<T> | null`**: `request`, `response` (or `null` for `dataProvider(...)` resolution without HTTP), and typed `result`.
4
-
5
- Pass an [`Endpoint<T>`](#docs/_misc/endpoint.md/endpoint) as the first argument. Import `get` and `ApiGetResult` from `@supersoniks/concorde/decorators`, and `Endpoint` from `@supersoniks/concorde/utils/endpoint`.
6
-
7
- ## Configuration
8
-
9
- - **Default:** `HTML.getApiConfiguration(host)` (ancestor `serviceURL`, etc.).
10
- - **Second argument:** `DataProviderKey<APIConfiguration>` — config is read from the publisher at the resolved path; internal mutations trigger another GET. See [API configuration](#docs/_misc/api-configuration.md/api-configuration) for mock demos.
11
-
12
- ## When the GET runs again
13
-
14
- - A referenced Lit property changes (endpoint path and/or config key contains `${...}`).
15
- - `set` on the active configuration publisher (`onInternalMutation`).
16
-
17
- ## Import
18
-
19
- <sonic-code language="typescript">
20
- <template>
21
- import { get, type ApiGetResult } from "@supersoniks/concorde/decorators";
22
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
23
- import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
24
- </template>
25
- </sonic-code>
26
-
27
- ## Minimal example
28
-
29
- Same demo service as [`sonic-queue`](../../core/components/functional/queue/queue.demo.ts) (`/docs-mock-api/geo/`). Publisher setup lives in `decorators-demo-geo.ts` and `decorators-demo-subscribe-publish-get-demos.ts`.
30
-
31
- <sonic-code language="typescript">
32
- <template>
33
- @get(new Endpoint<User>("users/${userId}"))
34
- @state()
35
- payload: ApiGetResult<User> | null = null;
36
- </template>
37
- </sonic-code>
38
-
39
- ## Live demos
40
-
41
- <sonic-code>
42
- <template>
43
- <docs-demo-sources for="demo-api-get"></docs-demo-sources>
44
- <demo-api-get></demo-api-get>
45
- </template>
46
- </sonic-code>
47
-
48
- Dynamic config and endpoint path (`demo-api-get-configuration-key` in doc sources):
49
-
50
- <sonic-code>
51
- <template>
52
- <docs-demo-sources for="demo-api-get-configuration-key"></docs-demo-sources>
53
- <demo-api-get-configuration-key></demo-api-get-configuration-key>
54
- </template>
55
- </sonic-code>
56
-
57
- Scoped `@get` with `@publish` / `@subscribe` on the payload (see [@publish](#docs/_decorators/publish.md/publish) and [@subscribe](#docs/_decorators/subscribe.md/subscribe)) — wrap under an ancestor with `serviceURL="/docs-mock-api/geo/"`:
58
-
59
- <sonic-code>
60
- <template>
61
- <div serviceURL="/docs-mock-api/geo/">
62
- <docs-demo-sources for="demo-api-get-publish-subscribe"></docs-demo-sources>
63
- <demo-api-get-publish-subscribe></demo-api-get-publish-subscribe>
64
- </div>
65
- </template>
66
- </sonic-code>
67
-
68
- Stale responses are ignored if the path or generation changed before the request finished.
@@ -1,171 +0,0 @@
1
- # @handle
2
-
3
- Typed callback on one or more `DataProviderKey<T>` paths: invokes the decorated **method** when a publisher assigns a value (calculations, side effects, updating other `@state` properties, etc.).
4
-
5
- Unlike [@subscribe](#docs/_decorators/subscribe.md/subscribe), nothing is bound to the decorated member — only your method runs. `@handle` is typed and accepts up to **3 keys** plus an optional trailing `HandleOptions` object. It supersedes the string-based [@onAssign](#docs/_decorators/on-assign.md/on-assign).
6
-
7
- By default the method is called on **every** assignment, even when the value is `null` / `undefined`. Use the options below to restrict that.
8
-
9
- ## Import
10
-
11
- <sonic-code language="typescript">
12
- <template>
13
- import { handle, Skip } from "@supersoniks/concorde/decorators";
14
- import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
15
- import { get, set } from "@supersoniks/concorde/utils";
16
- </template>
17
- </sonic-code>
18
-
19
- ## Basic example
20
-
21
- <sonic-code language="typescript">
22
- <template>
23
- type DemoCounterData = { count: number };
24
- const demoDataKey = new DataProviderKey&lt;DemoCounterData&gt;("demoData");
25
-
26
- @customElement("demo-handle")
27
- export class DemoHandle extends LitElement {
28
- @state() doubled = 0;
29
- @state() lastUpdate = "";
30
-
31
- @handle(demoDataKey.count)
32
- onCountChange(count: number) {
33
- this.doubled = count * 2;
34
- this.lastUpdate = new Date().toLocaleTimeString();
35
- }
36
-
37
- incrementCount() {
38
- const data = get(demoDataKey);
39
- set(demoDataKey, { ...data, count: data.count + 1 });
40
- }
41
-
42
- render() {
43
- return html`
44
- &lt;p&gt;Doubled count: ${this.doubled}&lt;/p&gt;
45
- &lt;p&gt;&lt;small&gt;Last update: ${this.lastUpdate}&lt;/small&gt;&lt;/p&gt;
46
- &lt;sonic-button @click=${this.incrementCount}&gt;Increment&lt;/sonic-button&gt;
47
- `;
48
- }
49
- }
50
- </template>
51
- </sonic-code>
52
-
53
- <sonic-code>
54
- <template>
55
- <docs-demo-sources for="demo-handle"></docs-demo-sources>
56
- <demo-handle></demo-handle>
57
- </template>
58
- </sonic-code>
59
-
60
- ## Dynamic path
61
-
62
- Placeholders in `DataProviderKey` resolve from the host component’s properties (same rules as `@bind` / `@subscribe`).
63
-
64
- <sonic-code language="typescript">
65
- <template>
66
- type User = { firstName: string; lastName: string; email: string };
67
-
68
- @customElement("demo-handle-dynamic")
69
- export class DemoHandleDynamic extends LitElement {
70
- @property({ type: Number })
71
- userIndex = 0;
72
-
73
- @state() displayName = "";
74
- @state() lastUpdate = "";
75
-
76
- @handle(new DataProviderKey&lt;User, { userIndex: number }&gt;("demoUsers.${userIndex}"))
77
- onUserAssigned(user: User) {
78
- this.displayName = `${user.firstName} ${user.lastName}`;
79
- this.lastUpdate = new Date().toLocaleTimeString();
80
- }
81
-
82
- render() {
83
- return html`...`;
84
- }
85
- }
86
- </template>
87
- </sonic-code>
88
-
89
- <sonic-code>
90
- <template>
91
- <docs-demo-sources for="demo-handle-dynamic"></docs-demo-sources>
92
- <demo-handle-dynamic></demo-handle-dynamic>
93
- </template>
94
- </sonic-code>
95
-
96
- ## Multiple paths
97
-
98
- `@handle` accepts up to **3 keys**; the method receives one strongly-typed argument per key, in order. Each assignment triggers the method, so make your method safe against partial values (or use `waitForAllDefined`, see below).
99
-
100
- <sonic-code language="typescript">
101
- <template>
102
- type QueueConfig = { onInactivity: { stillHere: { show: boolean } } };
103
- const config = new DataProviderKey&lt;QueueConfig&gt;("sessionQueueConfig");
104
- const idle = new DataProviderKey&lt;{ isIdle: boolean }&gt;("idleStatus");
105
-
106
- @customElement("demo-handle-multi")
107
- export class DemoHandleMulti extends LitElement {
108
-
109
- // show: boolean, isIdle: boolean — fully typed from the keys
110
- @handle(config.onInactivity.stillHere.show, idle.isIdle)
111
- onInactivity(show: boolean, isIdle: boolean) {
112
- if (show === true && isIdle === true) this.openModal();
113
- else this.closeModal();
114
- }
115
- }
116
- </template>
117
- </sonic-code>
118
-
119
- ## Options (`HandleOptions`)
120
-
121
- Pass an options object as the **last** argument. The names map to real situations seen in the apps.
122
-
123
- ### `waitForAllDefined`
124
-
125
- Only call the method once **all** watched keys are defined (non `null` / `undefined`). This reproduces the historical `@onAssign` semantics — use it when the logic only makes sense with every source ready (e.g. building a date from `date` + `timeZone` + `direction`).
126
-
127
- <sonic-code language="typescript">
128
- <template>
129
- @handle(trip.departureDate, trip.event.timeZone, form.direction, {
130
- waitForAllDefined: true,
131
- })
132
- updateDepartureDate(date: number, timeZone: string, direction: string) {
133
- // called only when the three values are all available
134
- this.formDate = formatDate(date, timeZone, direction);
135
- }
136
- </template>
137
- </sonic-code>
138
-
139
- ### `skip`
140
-
141
- Do **not** call the method when a received value belongs to one of the listed **categories** (the `Skip` enum). Each entry is a named category — not a value — so there is no value/pattern ambiguity (e.g. `{}` is `Skip.EmptyObject`, an explicit "empty object" category, never a value comparison).
142
-
143
- | Category | Matches |
144
- | --- | --- |
145
- | `Skip.Nullish` | `null` or `undefined` (a publisher always emits `null`, never `undefined`) |
146
- | `Skip.EmptyString` | `""` |
147
- | `Skip.EmptyObject` | object with no keys (`{}`), arrays excluded |
148
- | `Skip.EmptyArray` | empty array (`[]`) |
149
-
150
- Useful when a not-yet-initialized publisher emits `{}` as a "loading" state. For a **specific value** (e.g. a particular string), guard inside the method instead.
151
-
152
- <sonic-code language="typescript">
153
- <template>
154
- @handle(user.profile, { skip: [Skip.Nullish, Skip.EmptyObject] })
155
- onProfile(profile: Profile) {
156
- // not called while the publisher still holds {} (not loaded yet)
157
- this.displayName = profile.firstName;
158
- }
159
- </template>
160
- </sonic-code>
161
-
162
- > Options can be combined, e.g. `@handle(a, b, { waitForAllDefined: true, skip: [Skip.Nullish] })`. For any **arbitrary** validation on a specific value, just guard inside the method (`if (!isValid(v)) return;`) — that is exactly what an `accept`-style predicate would do, since `@handle` only runs your method.
163
-
164
- ## Highlights
165
-
166
- - Strict typing: the method receives one argument per key, in order.
167
- - Up to 3 keys; for 4+ keys (rare), keep [@onAssign](#docs/_decorators/on-assign.md/on-assign) for now.
168
- - By default the method runs on **every** assignment, even with `null` / `undefined` (unlike `@onAssign`, which waits for all values). Opt back into that behavior with `waitForAllDefined`.
169
- - `skip` filters out values by **named category** (e.g. `[Skip.Nullish, Skip.EmptyObject]`); for arbitrary checks on a specific value, guard inside the method.
170
-
171
- See also [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey).