@alwatr/action 9.12.0 → 9.13.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 CHANGED
@@ -2,9 +2,7 @@
2
2
 
3
3
  **Declarative DOM action-dispatch — the Action layer for Unidirectional Data Flow.**
4
4
 
5
- `@alwatr/action` bridges HTML attributes to typed signal handlers. Add an `on-action` attribute to any element, and the library automatically listens for the specified DOM event, resolves the payload, and dispatches a named action signal. Subscribe to actions anywhere in your app with `onAction`.
6
-
7
- This package serves as the **Action layer** in a Unidirectional Data Flow (UDF) architecture: UI elements declare their intent via `on-action` attributes, actions flow upward to business logic via `dispatchAction`, and state flows back down to the UI through signals.
5
+ `@alwatr/action` bridges HTML `on-action` attributes to typed signal handlers using **global event delegation**. One listener on `document.body` covers every element on the page including elements added dynamically after bootstrap with O(1) initialization cost regardless of how many elements exist.
8
6
 
9
7
  ---
10
8
 
@@ -12,82 +10,95 @@ This package serves as the **Action layer** in a Unidirectional Data Flow (UDF)
12
10
 
13
11
  | Approach | Problem |
14
12
  | -------------------------------------- | -------------------------------------------------------- |
15
- | Inline `addEventListener` everywhere | Scattered, hard to trace, breaks on dynamic content |
13
+ | Inline `addEventListener` everywhere | O(N) boot cost, scattered, breaks on dynamic content |
16
14
  | Framework event bindings (React, Vue…) | Requires full framework buy-in |
17
15
  | Custom events + `dispatchEvent` | Verbose, no typed payload, no central subscription point |
18
- | **`@alwatr/action`** | ✅ Declarative, typed, zero-coupling, SPA-friendly |
16
+ | **`@alwatr/action`** | ✅ O(1) boot, declarative, typed, zero-coupling |
19
17
 
20
18
  ---
21
19
 
22
- ## Installation
20
+ ## How It Works
23
21
 
24
- ```bash
25
- bun add @alwatr/action
26
- # or
27
- npm i @alwatr/action
28
- ```
22
+ ### Global Event Delegation
29
23
 
30
- ---
31
-
32
- ## Attribute Syntax
24
+ Instead of attaching one listener per element, a single capture-phase listener is registered on `document.body` for each event type. When an event fires anywhere on the page, the handler walks up from `event.target` using `closest('[on-action]')` to find the nearest element with an `on-action` attribute, parses the attribute, runs modifiers, resolves the payload, and calls `dispatchAction`.
33
25
 
34
26
  ```
35
- on-action="eventType->actionId"
36
- on-action="eventType->actionId:payload"
27
+ User clicks a button
28
+
29
+
30
+ document.body capture listener (1 listener total)
31
+
32
+ └─ closest('[on-action]') → finds element
33
+ parse attribute → 'click->add-to-cart:42'
34
+ run modifiers → none
35
+ resolve payload → '42'
36
+ dispatchAction('add-to-cart', '42')
37
+
38
+
39
+ ChannelSignal.dispatch('add-to-cart', '42') [O(1)]
40
+
41
+ └─ Map.get('add-to-cart') → invoke only matching handlers
37
42
  ```
38
43
 
39
- | Segment | Description | Example |
40
- | ----------- | ------------------------------------------------------------ | ----------------------------- |
41
- | `eventType` | Any standard DOM event name | `click`, `input`, `submit` |
42
- | `actionId` | Identifier your handler subscribes to | `open-drawer`, `search-query` |
43
- | `:payload` | Optional literal string, or `$value` to read `element.value` | `:main`, `:$value` |
44
+ ### Complexity
44
45
 
45
- ### Payload resolvers
46
+ | Metric | Per-element listeners | Global delegation |
47
+ | --------------- | --------------------- | -------------------- |
48
+ | Boot time | O(N elements) | **O(1)** |
49
+ | Memory | O(N listeners) | **O(1)** |
50
+ | Dynamic content | Requires re-bootstrap | **Works out-of-box** |
46
51
 
47
- | Token | Resolves to |
48
- | ------------ | -------------------------------------------------------------- |
49
- | `:$value` | `element.value` (for `<input>`, `<select>`, `<textarea>`) |
50
- | `:$formdata` | `Object.fromEntries(new FormData(form))` from nearest `<form>` |
52
+ ### Action Bus
53
+
54
+ The action bus is powered by a [`ChannelSignal`](../signal/README.md) from `@alwatr/signal`. Dispatching action `'A'` performs a single `Map.get('A')` lookup and invokes only the handlers registered for that specific action — **O(1) per dispatch**, regardless of how many other actions are subscribed.
51
55
 
52
- ### Event modifiers
56
+ ---
53
57
 
54
- Modifiers are chained with `.` after the event type:
58
+ ## Installation
55
59
 
56
- | Modifier | Behavior |
57
- | ----------- | -------------------------------------------------------------------- |
58
- | `.prevent` | Calls `event.preventDefault()` |
59
- | `.stop` | Calls `event.stopPropagation()` |
60
- | `.once` | Removes the listener after the first dispatch (native `once` option) |
61
- | `.passive` | Marks the listener as passive (cannot be combined with `.prevent`) |
62
- | `.validate` | Cancels dispatch if the nearest `<form>` fails `checkValidity()` |
60
+ ```bash
61
+ bun add @alwatr/action
62
+ # or
63
+ npm i @alwatr/action
64
+ ```
63
65
 
64
66
  ---
65
67
 
66
68
  ## Quick Start
67
69
 
68
- ### 1. Register the directive and bootstrap
70
+ ### 1. Register your action types
69
71
 
70
- ```typescript
71
- import {bootstrapDirectives} from '@alwatr/directive';
72
- import {registerActionDirective} from '@alwatr/action';
72
+ Create a declaration file in your package to extend `ActionRecord`. This gives you full type safety and IDE autocomplete across the entire app:
73
73
 
74
- registerActionDirective(); // registers ActionDirective under 'on-action'
75
- bootstrapDirectives();
74
+ ```ts
75
+ // src/action-record.ts
76
+ declare module '@alwatr/action' {
77
+ interface ActionRecord {
78
+ 'open-drawer': string;
79
+ 'search-query': string;
80
+ 'add-to-cart': {productId: number; qty: number};
81
+ 'logout': void;
82
+ }
83
+ }
76
84
  ```
77
85
 
78
- ### 2. Subscribe to actions
86
+ Passing an action name not declared in `ActionRecord` is a **compile error** — there is no string fallback.
79
87
 
80
- ```typescript
81
- import {onAction} from '@alwatr/action';
88
+ ### 2. Bootstrap delegation
82
89
 
83
- // Fires whenever any element with on-action="click->open-drawer:main" is clicked
84
- onAction('open-drawer', (payload) => {
85
- openDrawer(payload); // payload === 'main'
86
- });
90
+ ```ts
91
+ import {setupActionDelegation, onAction} from '@alwatr/action';
92
+ import './action-record.js'; // ensure the declaration is loaded
87
93
 
88
- // Fires on every keystroke in an input with on-action="input->search-query:$value"
89
- onAction('search-query', (query) => {
90
- performSearch(query);
94
+ // One call the entire page is covered, including future dynamic content.
95
+ setupActionDelegation();
96
+
97
+ // Payload types are inferred automatically from ActionRecord — no generics needed.
98
+ onAction('open-drawer', (panel) => openDrawer(panel)); // panel: string
99
+ onAction('search-query', (query) => performSearch(query)); // query: string
100
+ onAction('add-to-cart', (item) => {
101
+ cartService.add(item.productId, item.qty); // fully typed, no `!`
91
102
  });
92
103
  ```
93
104
 
@@ -97,9 +108,6 @@ onAction('search-query', (query) => {
97
108
  <!-- Dispatches 'open-drawer' with payload 'main' on click -->
98
109
  <button on-action="click->open-drawer:main">Open Drawer</button>
99
110
 
100
- <!-- Dispatches 'open-drawer' with payload 'settings' on click -->
101
- <button on-action="click->open-drawer:settings">Settings</button>
102
-
103
111
  <!-- Dispatches 'search-query' with the input's live value -->
104
112
  <input
105
113
  type="search"
@@ -107,99 +115,175 @@ onAction('search-query', (query) => {
107
115
  placeholder="Search…"
108
116
  />
109
117
 
110
- <!-- Prevents default and validates form before dispatching all field values -->
118
+ <!-- Prevents default, validates, then dispatches all field values -->
111
119
  <form
112
120
  on-action="submit.prevent.validate->submit-form:$formdata"
113
121
  novalidate
114
122
  >
115
- <!-- ... -->
123
+ <input
124
+ name="username"
125
+ required
126
+ />
127
+ <button type="submit">Save</button>
116
128
  </form>
117
129
  ```
118
130
 
119
- ---
120
-
121
- ## Programmatic Dispatch
131
+ ### 3. Programmatic dispatch
122
132
 
123
- Dispatch actions from code using `dispatchAction` — useful after async operations or from service layers:
124
-
125
- ```typescript
133
+ ```ts
126
134
  import {dispatchAction} from '@alwatr/action';
127
135
 
128
- dispatchAction('open-drawer', 'main');
129
- dispatchAction('navigate', '/home');
136
+ // Trigger actions from code — after async ops, from service layers, etc.
137
+ await uploadFile(file);
138
+ dispatchAction('upload-complete', fileId);
139
+
140
+ dispatchAction('navigate', '/dashboard');
130
141
  dispatchAction<{code: number}>('show-error', {code: 404});
131
142
  ```
132
143
 
133
144
  ---
134
145
 
146
+ ## Attribute Syntax
147
+
148
+ ```
149
+ on-action="eventType[.modifier…]->actionId[:payload]"
150
+ ```
151
+
152
+ | Segment | Description | Example |
153
+ | ----------- | --------------------------------------------------------- | ----------------------------- |
154
+ | `eventType` | Any standard DOM event name | `click`, `input`, `submit` |
155
+ | `modifier` | Optional dot-chained tokens processed before dispatch | `.prevent`, `.validate` |
156
+ | `actionId` | Identifier your handler subscribes to | `open-drawer`, `search-query` |
157
+ | `:payload` | Optional literal string, or a `$`-prefixed resolver token | `:main`, `:$value` |
158
+
159
+ ### Built-in modifiers
160
+
161
+ | Modifier | Behavior |
162
+ | ----------- | -------------------------------------------------------------------- |
163
+ | `.prevent` | Calls `event.preventDefault()` |
164
+ | `.stop` | Calls `event.stopPropagation()` |
165
+ | `.once` | Dispatches the action only once per element (emulated via `WeakSet`) |
166
+ | `.validate` | Cancels dispatch if the nearest `<form>` fails `checkValidity()` |
167
+
168
+ > **Note:** `.passive` is not supported in delegation mode because all delegated
169
+ > listeners must be non-passive to allow `.prevent` to work.
170
+
171
+ ### Built-in payload resolvers
172
+
173
+ | Token | Resolves to |
174
+ | ------------ | -------------------------------------------------------------- |
175
+ | `:$value` | `element.value` (for `<input>`, `<select>`, `<textarea>`) |
176
+ | `:$formdata` | `Object.fromEntries(new FormData(form))` from nearest `<form>` |
177
+
178
+ ---
179
+
135
180
  ## API Reference
136
181
 
137
- ### `onAction(actionId, handler)`
182
+ ### `ActionRecord` (interface)
138
183
 
139
- Subscribes to a named action dispatched by any `on-action` directive or `dispatchAction` call.
184
+ The global action type registry. Extend it via declaration merging to register your application's actions and unlock full type safety in `onAction` and `dispatchAction`.
140
185
 
141
- ```typescript
142
- function onAction<T = string>(actionId: string, handler: (payload?: T) => void): SubscribeResult;
186
+ ```ts
187
+ // src/action-record.ts
188
+ declare module '@alwatr/action' {
189
+ interface ActionRecord {
190
+ 'open-drawer': string;
191
+ 'add-to-cart': {productId: number; qty: number};
192
+ 'logout': void;
193
+ }
194
+ }
143
195
  ```
144
196
 
145
- | Parameter | Type | Description |
146
- | ---------- | ----------------------- | ----------------------------------- |
147
- | `actionId` | `string` | The action identifier to listen for |
148
- | `handler` | `(payload?: T) => void` | Called with the resolved payload |
197
+ Once declared:
149
198
 
150
- Returns a `SubscribeResult` with an `unsubscribe()` method.
199
+ - `onAction('open-drawer', (panel) => …)``panel` is inferred as `string`
200
+ - `dispatchAction('add-to-cart', {productId: 42, qty: 1})` — payload type enforced
201
+ - `dispatchAction('unknown-action', …)` — **compile error**
151
202
 
152
- ```typescript
153
- const sub = onAction('open-drawer', (payload) => {
154
- /* … */
155
- });
203
+ ---
156
204
 
157
- // Stop listening when no longer needed (prevents memory leaks)
158
- sub.unsubscribe();
205
+ ### `setupActionDelegation(eventTypes?)`
206
+
207
+ Registers global event delegation on `document.body`. Call once at bootstrap.
208
+ Subsequent calls with the same event types are no-ops (idempotent).
209
+
210
+ ```ts
211
+ function setupActionDelegation(eventTypes?: readonly string[]): void;
212
+ ```
213
+
214
+ Defaults to `DEFAULT_DELEGATED_EVENTS`: `['click', 'submit', 'input', 'change']`.
215
+
216
+ ```ts
217
+ import {setupActionDelegation, DEFAULT_DELEGATED_EVENTS} from '@alwatr/action';
218
+
219
+ // Default events
220
+ setupActionDelegation();
221
+
222
+ // Add extra event types
223
+ setupActionDelegation([...DEFAULT_DELEGATED_EVENTS, 'keydown', 'pointerup']);
159
224
  ```
160
225
 
161
226
  ---
162
227
 
163
- ### `dispatchAction(actionId, payload?)`
228
+ ### `teardownActionDelegation()`
164
229
 
165
- Dispatches a named action signal. Any `onAction` subscriber with a matching `actionId` will be invoked.
230
+ Removes all delegation listeners. Useful in tests or micro-frontend teardown.
166
231
 
167
- ```typescript
168
- function dispatchAction<T = string>(actionId: string, actionPayload?: T): void;
232
+ ```ts
233
+ function teardownActionDelegation(): void;
169
234
  ```
170
235
 
171
236
  ---
172
237
 
173
- ### `registerActionDirective()`
238
+ ### `onAction(actionId, handler)`
174
239
 
175
- Lazy registration for `ActionDirective`. Call once before `bootstrapDirectives()`.
176
- If never called, the entire directive module is tree-shaken from the bundle.
240
+ Subscribes to a named action. Uses `ChannelSignal.on()` for O(1) routing.
177
241
 
178
- ```typescript
179
- import {registerActionDirective} from '@alwatr/action';
180
- import {bootstrapDirectives} from '@alwatr/directive';
242
+ ```ts
243
+ function onAction<T = string>(actionId: string, handler: (payload?: T) => void): SubscribeResult;
244
+ ```
181
245
 
182
- registerActionDirective();
183
- bootstrapDirectives();
246
+ ```ts
247
+ const sub = onAction('open-drawer', (panel) => openDrawer(panel));
248
+
249
+ // Unsubscribe when no longer needed (prevents memory leaks)
250
+ sub.unsubscribe();
184
251
  ```
185
252
 
186
253
  ---
187
254
 
188
- ### `registerPageIdDirective()`
255
+ ### `dispatchAction(actionId, payload?)`
256
+
257
+ Dispatches a named action to all matching `onAction` subscribers.
189
258
 
190
- Registers the `page-id` directive, which dispatches a `'page-ready'` action with the page ID as payload when the element is initialized.
259
+ ```ts
260
+ function dispatchAction<T = string>(actionId: string, actionPayload?: T): void;
261
+ ```
262
+
263
+ ---
264
+
265
+ ### `dispatchPageId(element?)`
266
+
267
+ Reads the `page-id` attribute from `element` (defaults to `document.body`) and
268
+ dispatches a `'page-ready'` action with the page identifier as payload.
269
+
270
+ ```ts
271
+ function dispatchPageId(element?: HTMLElement): void;
272
+ ```
191
273
 
192
274
  ```html
193
- <body page-id="home"></body>
275
+ <body page-id="home">
276
+
277
+ </body>
194
278
  ```
195
279
 
196
- ```typescript
197
- import {registerPageIdDirective, onAction} from '@alwatr/action';
280
+ ```ts
281
+ import {dispatchPageId, onAction} from '@alwatr/action';
198
282
 
199
- registerPageIdDirective();
283
+ dispatchPageId(); // → dispatchAction('page-ready', 'home')
200
284
 
201
285
  onAction('page-ready', (pageId) => {
202
- console.log('Page is ready:', pageId); // 'home'
286
+ console.log('navigated to:', pageId); // 'home'
203
287
  });
204
288
  ```
205
289
 
@@ -207,9 +291,10 @@ onAction('page-ready', (pageId) => {
207
291
 
208
292
  ### `registerModifier(name, handler)`
209
293
 
210
- Registers a custom modifier for use in `on-action` directives. Return `false` from the handler to cancel the dispatch.
294
+ Registers a custom modifier. Return `false` to cancel the dispatch.
295
+ Works with both delegation and programmatic dispatch.
211
296
 
212
- ```typescript
297
+ ```ts
213
298
  import {registerModifier} from '@alwatr/action';
214
299
 
215
300
  registerModifier('confirm', function () {
@@ -221,17 +306,26 @@ registerModifier('confirm', function () {
221
306
  <button on-action="click.confirm->delete-item:42">Delete</button>
222
307
  ```
223
308
 
309
+ The handler receives an `ActionContext` as `this`:
310
+
311
+ ```ts
312
+ interface ActionContext {
313
+ readonly element: HTMLElement; // the element with the on-action attribute
314
+ }
315
+ ```
316
+
224
317
  ---
225
318
 
226
319
  ### `registerPayloadResolver(name, resolver)`
227
320
 
228
- Registers a custom payload resolver for use in `on-action` directives.
321
+ Registers a custom payload resolver. The return value becomes the action payload.
322
+ Works with both delegation and programmatic dispatch.
229
323
 
230
- ```typescript
324
+ ```ts
231
325
  import {registerPayloadResolver} from '@alwatr/action';
232
326
 
233
327
  registerPayloadResolver('$checked', function () {
234
- return (this.element_ as HTMLInputElement).checked;
328
+ return (this.element as HTMLInputElement).checked;
235
329
  });
236
330
  ```
237
331
 
@@ -244,14 +338,6 @@ registerPayloadResolver('$checked', function () {
244
338
 
245
339
  ---
246
340
 
247
- ### `ActionDirective`
248
-
249
- The directive class registered under the `on-action` attribute. Extends `Directive` from `@alwatr/directive`.
250
-
251
- You rarely need to interact with this class directly — use `registerActionDirective()` to register it.
252
-
253
- ---
254
-
255
341
  ## Unidirectional Data Flow
256
342
 
257
343
  ```
@@ -259,13 +345,15 @@ You rarely need to interact with this class directly — use `registerActionDire
259
345
  │ UI Layer │
260
346
  │ <button on-action="click->add-to-cart:42">Add</button> │
261
347
  └────────────────────────┬────────────────────────────────┘
262
- │ DOM event
348
+ │ DOM event bubbles to body
263
349
 
264
350
  ┌─────────────────────────────────────────────────────────┐
265
- Action Layer (@alwatr/action)
266
- dispatchAction('add-to-cart', '42')
351
+ Action Layer (@alwatr/action)
352
+ document.body capture listener (1 listener total)
353
+ │ → closest('[on-action]') → parse → run modifiers │
354
+ │ → dispatchAction('add-to-cart', '42') [O(1)] │
267
355
  └────────────────────────┬────────────────────────────────┘
268
- │ action signal
356
+ │ action signal (O(1) routing)
269
357
 
270
358
  ┌─────────────────────────────────────────────────────────┐
271
359
  │ Business Logic Layer │
@@ -275,45 +363,72 @@ You rarely need to interact with this class directly — use `registerActionDire
275
363
 
276
364
  ┌─────────────────────────────────────────────────────────┐
277
365
  │ State Layer (@alwatr/signal) │
278
- │ cartSignal.dispatch(newCartState)
366
+ │ cartSignal.set(newCartState)
279
367
  └────────────────────────┬────────────────────────────────┘
280
368
  │ state flows down to UI
281
369
 
282
- UI Layer
370
+ UI re-renders
283
371
  ```
284
372
 
285
373
  ---
286
374
 
287
- ## Lifecycle
375
+ ## Migration from Previous Versions
376
+
377
+ ### `registerActionDirective` / `registerPageIdDirective` removed
378
+
379
+ The directive-based approach has been replaced by global delegation.
380
+
381
+ **Before:**
288
382
 
383
+ ```ts
384
+ import {registerActionDirective, registerPageIdDirective} from '@alwatr/action';
385
+ import {bootstrapDirectives} from '@alwatr/directive';
386
+
387
+ registerActionDirective();
388
+ registerPageIdDirective();
389
+ bootstrapDirectives();
289
390
  ```
290
- bootstrapDirectives()
291
-
292
- └─ finds element with on-action="click->open-drawer:main"
293
-
294
- └─ new ActionDirective(element, 'on-action')
295
-
296
- └─ after one macrotask → init_()
297
-
298
- ├─ parse attributeValue with syntaxRegex
299
- ├─ if invalid → log accident, return
300
- └─ addEventListener(eventType, dispatch_)
301
- addDestroyHook(removeEventListener)
391
+
392
+ **After:**
393
+
394
+ ```ts
395
+ import {setupActionDelegation, dispatchPageId} from '@alwatr/action';
396
+
397
+ setupActionDelegation();
398
+ dispatchPageId();
302
399
  ```
303
400
 
304
- ---
401
+ ### `ActionDirective` / `PageIdDirective` removed
402
+
403
+ These classes are no longer exported. Use `setupActionDelegation()` and
404
+ `dispatchPageId()` instead.
305
405
 
306
- ## Cleanup & Memory Management
406
+ ### `ModifierHandler` / `PayloadResolver` context changed
307
407
 
308
- Every `addEventListener` registered by the directive has a corresponding `removeEventListener` in a destroy hook. Call `autoDestructDirectives()` periodically (or on route changes) to clean up directives whose elements have been removed from the DOM.
408
+ The `this` context in custom modifier and resolver functions changed from
409
+ `ActionDirective` to `ActionContext`:
309
410
 
310
- ```typescript
311
- import {autoDestructDirectives} from '@alwatr/directive';
411
+ **Before:**
312
412
 
313
- // Clean up on every SPA navigation
314
- router.on('navigate', autoDestructDirectives);
413
+ ```ts
414
+ registerModifier('not-disabled', function () {
415
+ return !(this.element_ as HTMLButtonElement).disabled; // this.element_
416
+ });
315
417
  ```
316
418
 
419
+ **After:**
420
+
421
+ ```ts
422
+ registerModifier('not-disabled', function () {
423
+ return !(this.element as HTMLButtonElement).disabled; // this.element (no underscore)
424
+ });
425
+ ```
426
+
427
+ ### `ActionSignalPayload` removed
428
+
429
+ This type was an implementation detail of the old `EventSignal`-based bus and
430
+ is no longer needed. Use `onAction` and `dispatchAction` directly.
431
+
317
432
  ---
318
433
 
319
434
  ## Contributing
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @file action-record.ts
3
+ *
4
+ * Global action type registry via TypeScript declaration merging.
5
+ *
6
+ * ## How it works
7
+ *
8
+ * `ActionRecord` is an open interface — any package in the monorepo (or any
9
+ * consumer application) can extend it with their own action names and payload
10
+ * types using declaration merging, without modifying this file:
11
+ *
12
+ * ```ts
13
+ * // In your package: src/action-record.ts
14
+ * declare module '@alwatr/action' {
15
+ * interface ActionRecord {
16
+ * 'open-drawer': string;
17
+ * 'add-to-cart': {productId: number; qty: number};
18
+ * 'logout': void;
19
+ * }
20
+ * }
21
+ * ```
22
+ *
23
+ * Once declared, `onAction` and `dispatchAction` become fully type-safe for
24
+ * those action names — the compiler enforces the correct payload type at every
25
+ * call site and provides autocomplete for action identifiers.
26
+ *
27
+ * Only actions declared in `ActionRecord` are accepted. Passing an unknown
28
+ * action name is a **compile error** — there is no string fallback.
29
+ */
30
+ /**
31
+ * Global registry mapping action identifiers to their payload types.
32
+ *
33
+ * Extend this interface via declaration merging to register your application's
34
+ * actions and gain full type safety in `onAction` and `dispatchAction`.
35
+ *
36
+ * Built-in system actions are declared here. Application-level actions should
37
+ * be declared in a dedicated `action-record.ts` file within each feature package.
38
+ *
39
+ * @example — registering actions in a feature package
40
+ * ```ts
41
+ * // pkg/my-feature/src/action-record.ts
42
+ * declare module '@alwatr/action' {
43
+ * interface ActionRecord {
44
+ * 'open-drawer': string;
45
+ * 'add-to-cart': {productId: number; qty: number};
46
+ * 'logout': void;
47
+ * }
48
+ * }
49
+ * ```
50
+ */
51
+ export interface ActionRecord {
52
+ /**
53
+ * Dispatched by `dispatchPageId()` when the page identity is read from the
54
+ * `page-id` HTML attribute. Payload is the page identifier string.
55
+ *
56
+ * @example
57
+ * ```html
58
+ * <body page-id="home">…</body>
59
+ * ```
60
+ * ```ts
61
+ * onAction('page-ready', (pageId) => router.setPage(pageId));
62
+ * ```
63
+ */
64
+ 'page-ready': string;
65
+ }
66
+ //# sourceMappingURL=action-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-record.d.ts","sourceRoot":"","sources":["../src/action-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;OAWG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB"}