@alwatr/action 9.14.0 → 9.17.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.
- package/README.md +335 -95
- package/dist/action-record.d.ts +4 -4
- package/dist/action.d.ts +93 -0
- package/dist/action.d.ts.map +1 -0
- package/dist/delegate.d.ts +33 -10
- package/dist/delegate.d.ts.map +1 -1
- package/dist/lib.d.ts +8 -6
- package/dist/lib.d.ts.map +1 -1
- package/dist/main.d.ts +47 -8
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -3
- package/dist/main.js.map +6 -6
- package/dist/method.d.ts +74 -57
- package/dist/method.d.ts.map +1 -1
- package/dist/registry.d.ts +28 -16
- package/dist/registry.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/action-record.ts +4 -4
- package/src/action.ts +97 -0
- package/src/delegate.ts +131 -86
- package/src/lib.ts +9 -6
- package/src/main.ts +47 -8
- package/src/method.ts +84 -66
- package/src/registry.ts +55 -24
package/src/method.ts
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
import type {Awaitable} from '@alwatr/type-helper';
|
|
2
|
-
import {internalChannel_, logger_} from './lib.js';
|
|
3
2
|
import type {SubscribeResult} from '@alwatr/signal';
|
|
3
|
+
|
|
4
|
+
import {internalChannel_, logger_} from './lib.js';
|
|
4
5
|
import {modifierRegistry, payloadRegistry, type ModifierHandler, type PayloadResolver} from './registry.js';
|
|
5
6
|
import type {ActionRecord} from './action-record.js';
|
|
7
|
+
import type {Action} from './action.js';
|
|
6
8
|
|
|
7
9
|
// Re-export extension types so consumers can import them from the package root.
|
|
8
10
|
export type {ModifierHandler, PayloadResolver};
|
|
11
|
+
export type {Action};
|
|
9
12
|
|
|
10
13
|
// ─── Core Action API ──────────────────────────────────────────────────────────
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* Subscribes to a named action dispatched anywhere in the application.
|
|
14
17
|
*
|
|
15
|
-
* `
|
|
16
|
-
*
|
|
17
|
-
* generic annotation needed
|
|
18
|
+
* `type` must be a key of `ActionRecord`. The handler receives the full
|
|
19
|
+
* `Action<K>` object — giving access to `payload`, `context`, and `meta`
|
|
20
|
+
* in one place. No manual generic annotation is needed; the compiler infers
|
|
21
|
+
* the correct `payload` type from `ActionRecord`:
|
|
18
22
|
*
|
|
19
23
|
* ```ts
|
|
20
|
-
* // ActionRecord declares: '
|
|
21
|
-
* onAction('
|
|
22
|
-
* cartService.add(
|
|
24
|
+
* // ActionRecord declares: 'add_to_cart': {productId: number; qty: number}
|
|
25
|
+
* onAction('add_to_cart', (action) => {
|
|
26
|
+
* cartService.add(action.payload.productId, action.payload.qty); // fully typed
|
|
27
|
+
* console.log(action.context); // e.g. 'product-list' (from DOM) or undefined
|
|
23
28
|
* });
|
|
24
29
|
* ```
|
|
25
30
|
*
|
|
@@ -30,7 +35,7 @@ export type {ModifierHandler, PayloadResolver};
|
|
|
30
35
|
* // src/action-record.ts
|
|
31
36
|
* declare module '@alwatr/action' {
|
|
32
37
|
* interface ActionRecord {
|
|
33
|
-
* '
|
|
38
|
+
* 'open_drawer': string;
|
|
34
39
|
* }
|
|
35
40
|
* }
|
|
36
41
|
* ```
|
|
@@ -38,99 +43,103 @@ export type {ModifierHandler, PayloadResolver};
|
|
|
38
43
|
* Internally delegates to `ChannelSignal.on()` for **O(1) routing** — dispatching
|
|
39
44
|
* action `'A'` never invokes handlers registered for action `'B'`.
|
|
40
45
|
*
|
|
41
|
-
* @param
|
|
42
|
-
* @param handler
|
|
46
|
+
* @param type - A key of `ActionRecord`.
|
|
47
|
+
* @param handler - Callback invoked with the full `Action<K>` on each dispatch.
|
|
43
48
|
* @returns A `SubscribeResult` with an `unsubscribe()` method for cleanup.
|
|
44
49
|
*
|
|
45
50
|
* @example
|
|
46
51
|
* ```ts
|
|
47
52
|
* import {onAction} from '@alwatr/action';
|
|
48
53
|
*
|
|
49
|
-
* const sub = onAction('
|
|
50
|
-
* router.setPage(
|
|
54
|
+
* const sub = onAction('page_ready', (action) => {
|
|
55
|
+
* router.setPage(action.payload); // payload: string — inferred from ActionRecord
|
|
51
56
|
* });
|
|
52
57
|
*
|
|
53
58
|
* sub.unsubscribe(); // stop listening when no longer needed
|
|
54
59
|
* ```
|
|
55
60
|
*/
|
|
56
61
|
export function onAction<K extends keyof ActionRecord>(
|
|
57
|
-
|
|
58
|
-
handler: (
|
|
62
|
+
type: K,
|
|
63
|
+
handler: (action: Action<K>) => Awaitable<void>,
|
|
59
64
|
): SubscribeResult {
|
|
60
|
-
logger_.logMethodArgs?.('onAction', {
|
|
61
|
-
|
|
65
|
+
logger_.logMethodArgs?.('onAction', {type});
|
|
66
|
+
// The internal channel stores Action<any>; we cast to Action<K> here because
|
|
67
|
+
// the channel key guarantees the type matches — only Action<K> objects are
|
|
68
|
+
// ever dispatched under key K.
|
|
69
|
+
return internalChannel_.on(type, handler as (action: Action) => Awaitable<void>);
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
/**
|
|
65
|
-
* Dispatches
|
|
73
|
+
* Dispatches an action to all `onAction` subscribers with a matching `type`.
|
|
66
74
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
75
|
+
* Accepts a full `Action<K>` object. The `payload` field is automatically
|
|
76
|
+
* typed from `ActionRecord[K]` — passing the wrong shape is a **compile error**:
|
|
69
77
|
*
|
|
70
78
|
* ```ts
|
|
71
|
-
* // ActionRecord declares: '
|
|
72
|
-
* dispatchAction('
|
|
73
|
-
* dispatchAction('
|
|
74
|
-
* dispatchAction('
|
|
79
|
+
* // ActionRecord declares: 'add_to_cart': {productId: number; qty: number}
|
|
80
|
+
* dispatchAction({type: 'add_to_cart', payload: {productId: 42, qty: 1}}); // ✅
|
|
81
|
+
* dispatchAction({type: 'add_to_cart', payload: 'wrong'}); // ❌ compile error
|
|
82
|
+
* dispatchAction({type: 'unknown_action', payload: 'x'}); // ❌ compile error
|
|
75
83
|
* ```
|
|
76
84
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* // src/action-record.ts
|
|
81
|
-
* declare module '@alwatr/action' {
|
|
82
|
-
* interface ActionRecord {
|
|
83
|
-
* 'navigate': string;
|
|
84
|
-
* 'logout': void;
|
|
85
|
-
* }
|
|
86
|
-
* }
|
|
87
|
-
* ```
|
|
85
|
+
* The `context` and `meta` fields are optional. When dispatching from code
|
|
86
|
+
* (not from the DOM), omit `context` — it is only meaningful for DOM-originated
|
|
87
|
+
* actions where an `[action-context]` ancestor exists.
|
|
88
88
|
*
|
|
89
89
|
* Use `dispatchAction` when triggering an action from code — e.g. after an
|
|
90
90
|
* async operation, from a service layer, or in tests. For DOM-driven actions,
|
|
91
|
-
* use the `on
|
|
91
|
+
* use the `on-<eventType>` HTML attribute with `setupActionDelegation`.
|
|
92
92
|
*
|
|
93
|
-
* @param
|
|
94
|
-
* @param actionPayload - The payload; type is enforced by `ActionRecord`.
|
|
93
|
+
* @param action - A full `Action<K>` object with at minimum `type` and `payload`.
|
|
95
94
|
*
|
|
96
95
|
* @example — with payload
|
|
97
96
|
* ```ts
|
|
98
97
|
* import {dispatchAction} from '@alwatr/action';
|
|
99
98
|
*
|
|
100
|
-
* dispatchAction('
|
|
101
|
-
* dispatchAction('
|
|
99
|
+
* dispatchAction({type: 'navigate', payload: '/dashboard'});
|
|
100
|
+
* dispatchAction({type: 'add_to_cart', payload: {productId: 42, qty: 1}});
|
|
102
101
|
* ```
|
|
103
102
|
*
|
|
104
|
-
* @example — void payload
|
|
103
|
+
* @example — void payload
|
|
105
104
|
* ```ts
|
|
106
|
-
* dispatchAction('logout');
|
|
105
|
+
* dispatchAction({type: 'logout', payload: undefined});
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @example — with context and meta
|
|
109
|
+
* ```ts
|
|
110
|
+
* dispatchAction({
|
|
111
|
+
* type: 'slider_change',
|
|
112
|
+
* payload: 75,
|
|
113
|
+
* context: 'volume_slider',
|
|
114
|
+
* meta: {traceId: 'abc-123'},
|
|
115
|
+
* });
|
|
107
116
|
* ```
|
|
108
117
|
*/
|
|
109
|
-
export function dispatchAction<K extends keyof ActionRecord>(
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
const [actionId, actionPayload] = args;
|
|
113
|
-
logger_.logMethodArgs?.('dispatchAction', {actionId, actionPayload});
|
|
114
|
-
internalChannel_.dispatch(actionId, actionPayload);
|
|
118
|
+
export function dispatchAction<K extends keyof ActionRecord>(action: Action<K>): void {
|
|
119
|
+
logger_.logMethodArgs?.('dispatchAction', action);
|
|
120
|
+
internalChannel_.dispatch(action.type, action);
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
// ─── Extension API ────────────────────────────────────────────────────────────
|
|
118
124
|
|
|
119
125
|
/**
|
|
120
|
-
* Registers a custom modifier that can be used in `on
|
|
126
|
+
* Registers a custom modifier that can be used in `on-<eventType>` attribute syntax.
|
|
121
127
|
*
|
|
122
|
-
* A modifier is a
|
|
123
|
-
* (e.g. `click
|
|
128
|
+
* A modifier is a comma-separated token placed after the `;` separator
|
|
129
|
+
* (e.g. `on-click="action-id; mymod"`). Its handler runs before the payload is
|
|
124
130
|
* resolved and the action is dispatched. Returning `false` cancels the dispatch.
|
|
125
131
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
132
|
+
* The handler also receives the **mutable** `action` object being built, so it
|
|
133
|
+
* can attach data to `action.meta` before the action reaches subscribers.
|
|
134
|
+
*
|
|
135
|
+
* Built-in modifiers (`prevent`, `validate`, `once`) are always available.
|
|
136
|
+
* This function lets you add domain-specific ones.
|
|
128
137
|
*
|
|
129
138
|
* Registering the same name twice logs an accident and overwrites the previous
|
|
130
139
|
* handler — avoid duplicate registrations in production code.
|
|
131
140
|
*
|
|
132
|
-
* @param name - The modifier token (lowercase, no
|
|
133
|
-
* @param handler - A `ModifierHandler` receiving `(event, element)`.
|
|
141
|
+
* @param name - The modifier token (lowercase, no special characters).
|
|
142
|
+
* @param handler - A `ModifierHandler` receiving `(event, element, action)`.
|
|
134
143
|
*
|
|
135
144
|
* @example — a `confirm` modifier that shows a browser dialog
|
|
136
145
|
* ```ts
|
|
@@ -139,7 +148,16 @@ export function dispatchAction<K extends keyof ActionRecord>(
|
|
|
139
148
|
* registerModifier('confirm', () => window.confirm('Are you sure?'));
|
|
140
149
|
* ```
|
|
141
150
|
* ```html
|
|
142
|
-
* <button on-
|
|
151
|
+
* <button on-click="delete_item:42; confirm">Delete</button>
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @example — a `trace` modifier that stamps a trace ID into meta
|
|
155
|
+
* ```ts
|
|
156
|
+
* registerModifier('trace', (_event, _element, action) => {
|
|
157
|
+
* action.meta ??= {};
|
|
158
|
+
* action.meta['traceId'] = crypto.randomUUID();
|
|
159
|
+
* return true;
|
|
160
|
+
* });
|
|
143
161
|
* ```
|
|
144
162
|
*/
|
|
145
163
|
export function registerModifier(name: string, handler: ModifierHandler): void {
|
|
@@ -151,15 +169,15 @@ export function registerModifier(name: string, handler: ModifierHandler): void {
|
|
|
151
169
|
}
|
|
152
170
|
|
|
153
171
|
/**
|
|
154
|
-
* Registers a custom payload resolver that can be used in `on
|
|
172
|
+
* Registers a custom payload resolver that can be used in `on-<eventType>` attribute syntax.
|
|
155
173
|
*
|
|
156
|
-
* A payload resolver is a colon-
|
|
157
|
-
* (e.g. `click
|
|
158
|
-
* with
|
|
159
|
-
*
|
|
174
|
+
* A payload resolver is a colon-prefixed token in the attribute value
|
|
175
|
+
* (e.g. `on-click="action-id:$mytoken"`). Its function is called at dispatch time
|
|
176
|
+
* with the DOM event and the element. The return value becomes the `payload`
|
|
177
|
+
* field of the `Action` object passed to `onAction` subscribers.
|
|
160
178
|
*
|
|
161
|
-
* Built-in resolvers (`$value`, `$formdata`) are always available.
|
|
162
|
-
* lets you add domain-specific ones.
|
|
179
|
+
* Built-in resolvers (`$value`, `$formdata`, `$checked`) are always available.
|
|
180
|
+
* This function lets you add domain-specific ones.
|
|
163
181
|
*
|
|
164
182
|
* Registering the same name twice logs an accident and overwrites the previous
|
|
165
183
|
* resolver — avoid duplicate registrations in production code.
|
|
@@ -167,16 +185,16 @@ export function registerModifier(name: string, handler: ModifierHandler): void {
|
|
|
167
185
|
* @param name - The resolver token (should start with `$` by convention).
|
|
168
186
|
* @param resolver - A `PayloadResolver` receiving `(event, element)`.
|
|
169
187
|
*
|
|
170
|
-
* @example — a `$
|
|
188
|
+
* @example — a `$data-id` resolver that reads a data attribute
|
|
171
189
|
* ```ts
|
|
172
190
|
* import {registerPayloadResolver} from '@alwatr/action';
|
|
173
191
|
*
|
|
174
|
-
* registerPayloadResolver('$
|
|
175
|
-
* return (element as
|
|
192
|
+
* registerPayloadResolver('$data-id', (_event, element) => {
|
|
193
|
+
* return (element as HTMLElement).dataset.id ?? null;
|
|
176
194
|
* });
|
|
177
195
|
* ```
|
|
178
196
|
* ```html
|
|
179
|
-
* <
|
|
197
|
+
* <button on-click="select_item:$data-id" data-id="42">Select</button>
|
|
180
198
|
* ```
|
|
181
199
|
*/
|
|
182
200
|
export function registerPayloadResolver(name: string, resolver: PayloadResolver): void {
|
package/src/registry.ts
CHANGED
|
@@ -1,38 +1,51 @@
|
|
|
1
|
+
import type {Action} from './action.js';
|
|
2
|
+
|
|
1
3
|
// ─── Type Definitions ────────────────────────────────────────────────────────
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
|
-
* A modifier handler used in `on
|
|
6
|
+
* A modifier handler used in `on-<eventType>` attribute syntax.
|
|
5
7
|
*
|
|
6
|
-
* Receives the triggering DOM `event
|
|
7
|
-
* `on
|
|
8
|
-
*
|
|
8
|
+
* Receives the triggering DOM `event`, the `element` that owns the
|
|
9
|
+
* `on-<eventType>` attribute, and the **mutable** `action` object being built.
|
|
10
|
+
* The handler may mutate `action.meta` to attach cross-cutting data (e.g. a
|
|
11
|
+
* trace ID, a timestamp, or an A/B flag) before the action reaches subscribers.
|
|
12
|
+
*
|
|
13
|
+
* Return `true` (or any truthy value) to allow the action to proceed, or
|
|
14
|
+
* `false` to cancel the dispatch entirely.
|
|
9
15
|
*
|
|
10
16
|
* Using explicit parameters instead of `this` binding makes handlers
|
|
11
17
|
* compatible with arrow functions and easier to test in isolation.
|
|
12
18
|
*
|
|
13
|
-
* @example
|
|
19
|
+
* @example — a modifier that stamps a timestamp into meta
|
|
20
|
+
* ```ts
|
|
21
|
+
* const timestampHandler: ModifierHandler = (_event, _element, action) => {
|
|
22
|
+
* action.meta ??= {};
|
|
23
|
+
* action.meta['timestamp'] = Date.now();
|
|
24
|
+
* return true;
|
|
25
|
+
* };
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example — a modifier that cancels dispatch when the element is disabled
|
|
14
29
|
* ```ts
|
|
15
|
-
* // A modifier that only allows the action when the element is not disabled
|
|
16
30
|
* const notDisabledHandler: ModifierHandler = (_event, element) => {
|
|
17
31
|
* return !(element as HTMLButtonElement).disabled;
|
|
18
32
|
* };
|
|
19
33
|
* ```
|
|
20
34
|
*/
|
|
21
|
-
export type ModifierHandler = (event: Event, element: HTMLElement) => boolean;
|
|
35
|
+
export type ModifierHandler = (event: Event, element: HTMLElement, action: Action) => boolean;
|
|
22
36
|
|
|
23
37
|
/**
|
|
24
|
-
* A payload resolver used in `on
|
|
38
|
+
* A payload resolver used in `on-<eventType>` attribute syntax.
|
|
25
39
|
*
|
|
26
40
|
* Receives the triggering DOM `event` and the `element` that owns the
|
|
27
|
-
* `on
|
|
28
|
-
*
|
|
41
|
+
* `on-<eventType>` attribute. The return value becomes the `payload` field of
|
|
42
|
+
* the `Action` object passed to `onAction` subscribers.
|
|
29
43
|
*
|
|
30
44
|
* Using explicit parameters instead of `this` binding makes resolvers
|
|
31
45
|
* compatible with arrow functions and easier to test in isolation.
|
|
32
46
|
*
|
|
33
|
-
* @example
|
|
47
|
+
* @example — a resolver that returns the element's dataset id
|
|
34
48
|
* ```ts
|
|
35
|
-
* // A resolver that returns the element's dataset id
|
|
36
49
|
* const dataIdResolver: PayloadResolver = (_event, element) => {
|
|
37
50
|
* return (element as HTMLElement).dataset.id ?? null;
|
|
38
51
|
* };
|
|
@@ -45,8 +58,8 @@ export type PayloadResolver = (event: Event, element: HTMLElement) => unknown;
|
|
|
45
58
|
/**
|
|
46
59
|
* Registry of all named modifier handlers.
|
|
47
60
|
*
|
|
48
|
-
* Keys are modifier names used in the `on
|
|
49
|
-
* (e.g. `click
|
|
61
|
+
* Keys are modifier names used in the `on-<eventType>` attribute syntax
|
|
62
|
+
* (e.g. `on-click="action-id; prevent"`). Values are `ModifierHandler` functions.
|
|
50
63
|
* Populated at module load with built-in modifiers; extended at runtime via
|
|
51
64
|
* `registerModifier`.
|
|
52
65
|
*
|
|
@@ -57,8 +70,8 @@ export const modifierRegistry = new Map<string, ModifierHandler>();
|
|
|
57
70
|
/**
|
|
58
71
|
* Registry of all named payload resolvers.
|
|
59
72
|
*
|
|
60
|
-
* Keys are resolver tokens used in the `on
|
|
61
|
-
* (e.g. `
|
|
73
|
+
* Keys are resolver tokens used in the `on-<eventType>` attribute syntax
|
|
74
|
+
* (e.g. `on-input="search_query:$value"`). Values are `PayloadResolver` functions.
|
|
62
75
|
* Populated at module load with built-in resolvers; extended at runtime via
|
|
63
76
|
* `registerPayloadResolver`.
|
|
64
77
|
*
|
|
@@ -74,7 +87,7 @@ export const payloadRegistry = new Map<string, PayloadResolver>();
|
|
|
74
87
|
* Use it to suppress the browser's default behaviour (e.g. form submission,
|
|
75
88
|
* link navigation, context menu).
|
|
76
89
|
*
|
|
77
|
-
* @example `<form on-
|
|
90
|
+
* @example `<form on-submit="submit-form; prevent">`
|
|
78
91
|
*/
|
|
79
92
|
modifierRegistry.set('prevent', (event) => {
|
|
80
93
|
event.preventDefault();
|
|
@@ -89,9 +102,9 @@ modifierRegistry.set('prevent', (event) => {
|
|
|
89
102
|
* allowing native constraint-validation UI to surface errors. If no form is
|
|
90
103
|
* found the dispatch is also cancelled.
|
|
91
104
|
*
|
|
92
|
-
* Pair with
|
|
105
|
+
* Pair with `prevent` on `submit` events to avoid page reloads:
|
|
93
106
|
*
|
|
94
|
-
* @example `<form on-
|
|
107
|
+
* @example `<form on-submit="submit_form:$formdata; prevent,validate" novalidate>`
|
|
95
108
|
*/
|
|
96
109
|
modifierRegistry.set('validate', (_event, element) => {
|
|
97
110
|
const form = element instanceof HTMLFormElement ? element : element.closest('form');
|
|
@@ -107,7 +120,7 @@ modifierRegistry.set('validate', (_event, element) => {
|
|
|
107
120
|
* Works with any element that exposes a `value` property: `<input>`,
|
|
108
121
|
* `<textarea>`, `<select>`. Returns `null` for elements without `.value`.
|
|
109
122
|
*
|
|
110
|
-
* @example `<input on-
|
|
123
|
+
* @example `<input on-input="search_query:$value" />`
|
|
111
124
|
*/
|
|
112
125
|
payloadRegistry.set('$value', (_event, element) => {
|
|
113
126
|
return 'value' in element ? (element as {value: unknown}).value : null;
|
|
@@ -120,14 +133,32 @@ payloadRegistry.set('$value', (_event, element) => {
|
|
|
120
133
|
* Looks for a `<form>` ancestor (or the element itself). Returns `null` when no
|
|
121
134
|
* form is found.
|
|
122
135
|
*
|
|
123
|
-
* @example `<form on-
|
|
136
|
+
* @example `<form on-submit="submit_form:$formdata; prevent,validate">`
|
|
124
137
|
* ```ts
|
|
125
|
-
* onAction('
|
|
126
|
-
* console.log(
|
|
138
|
+
* onAction('submit_form', (action) => {
|
|
139
|
+
* console.log(action.payload); // {username: 'ali', password: '…'}
|
|
127
140
|
* });
|
|
128
141
|
* ```
|
|
129
142
|
*/
|
|
130
143
|
payloadRegistry.set('$formdata', (_event, element) => {
|
|
131
144
|
const form = element instanceof HTMLFormElement ? element : element.closest('form');
|
|
132
|
-
return form ? Object.fromEntries(new FormData(form)
|
|
145
|
+
return form ? Object.fromEntries(new FormData(form)) : null;
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* `$checked` — resolves to the `.checked` boolean property of a checkbox or radio input.
|
|
150
|
+
*
|
|
151
|
+
* Works with `<input type="checkbox">` and `<input type="radio">`.
|
|
152
|
+
* Returns `null` for elements that do not have a `checked` property.
|
|
153
|
+
*
|
|
154
|
+
* @example `<input type="checkbox" on-change="toggle_feature:$checked" />`
|
|
155
|
+
* ```ts
|
|
156
|
+
* onAction('toggle_feature', (action) => {
|
|
157
|
+
* console.log(action.payload); // true or false
|
|
158
|
+
* featureSignal.set(action.payload);
|
|
159
|
+
* });
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
payloadRegistry.set('$checked', (_event, element) => {
|
|
163
|
+
return 'checked' in element ? (element as HTMLInputElement).checked : null;
|
|
133
164
|
});
|