@alwatr/action 9.16.0 → 9.18.1
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 +249 -70
- package/dist/delegate.d.ts +28 -5
- package/dist/delegate.d.ts.map +1 -1
- package/dist/{lib.d.ts → lib_.d.ts} +9 -7
- package/dist/lib_.d.ts.map +1 -0
- package/dist/main.d.ts +31 -5
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -3
- package/dist/main.js.map +7 -7
- package/dist/method.d.ts +63 -48
- package/dist/method.d.ts.map +1 -1
- package/dist/registry_.d.ts +24 -0
- package/dist/registry_.d.ts.map +1 -0
- package/dist/type.d.ts +160 -0
- package/dist/type.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/delegate.ts +71 -21
- package/src/{lib.ts → lib_.ts} +8 -6
- package/src/main.ts +31 -5
- package/src/method.ts +73 -58
- package/src/{registry.ts → registry_.ts} +7 -48
- package/src/type.ts +165 -0
- package/dist/action-record.d.ts +0 -54
- package/dist/action-record.d.ts.map +0 -1
- package/dist/lib.d.ts.map +0 -1
- package/dist/registry.d.ts +0 -61
- package/dist/registry.d.ts.map +0 -1
- package/src/action-record.ts +0 -54
package/src/type.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type {DictionaryOpt} from '@alwatr/type-helper';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Global registry mapping action identifiers to their payload types.
|
|
5
|
+
*
|
|
6
|
+
* Extend this interface via declaration merging to register your application's
|
|
7
|
+
* actions and gain full type safety in `onAction` and `dispatchAction`.
|
|
8
|
+
*
|
|
9
|
+
* This interface is intentionally empty in the base package — all actions are
|
|
10
|
+
* application-specific and should be declared in a dedicated `action-record.ts`
|
|
11
|
+
* file within each feature package.
|
|
12
|
+
*
|
|
13
|
+
* @example — registering actions in a feature package
|
|
14
|
+
* ```ts
|
|
15
|
+
* // pkg/my-feature/src/action-record.ts
|
|
16
|
+
* declare module '@alwatr/action' {
|
|
17
|
+
* interface ActionRecord {
|
|
18
|
+
* 'open_drawer': string;
|
|
19
|
+
* 'add_to_cart': {productId: number; qty: number};
|
|
20
|
+
* 'logout': void;
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export interface ActionRecord {}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Builds the parameter type for `dispatchAction`.
|
|
29
|
+
*
|
|
30
|
+
* When `ActionRecord[K]` is `void`, the `payload` field becomes optional so
|
|
31
|
+
* callers can omit it entirely. For all other payload types the field remains
|
|
32
|
+
* required, preserving full type safety.
|
|
33
|
+
*
|
|
34
|
+
* @example — void action (payload omitted)
|
|
35
|
+
* ```ts
|
|
36
|
+
* dispatchAction({type: 'logout'});
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example — typed action (payload required)
|
|
40
|
+
* ```ts
|
|
41
|
+
* dispatchAction({type: 'add_to_cart', payload: {productId: 42, qty: 1}});
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export type DispatchParam<K extends keyof ActionRecord> =
|
|
45
|
+
ActionRecord[K] extends void ? Omit<Action<K>, 'payload'> & {payload?: void} : Action<K>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Alwatr Flux Standard Action (AFSA).
|
|
49
|
+
*
|
|
50
|
+
* The single, canonical object passed to every `dispatchAction` call and
|
|
51
|
+
* received by every `onAction` handler. Keeping all action data in one
|
|
52
|
+
* structure makes the bus extensible without breaking existing call sites.
|
|
53
|
+
*
|
|
54
|
+
* @template K - A key of `ActionRecord`; constrains `type` and `payload` together.
|
|
55
|
+
*
|
|
56
|
+
* @example — dispatching
|
|
57
|
+
* ```ts
|
|
58
|
+
* dispatchAction({type: 'add_to_cart', payload: {productId: 42, qty: 1}});
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @example — subscribing
|
|
62
|
+
* ```ts
|
|
63
|
+
* onAction('add_to_cart', (action) => {
|
|
64
|
+
* console.log(action.type); // 'add_to_cart'
|
|
65
|
+
* console.log(action.payload); // {productId: 42, qty: 1}
|
|
66
|
+
* console.log(action.context); // e.g. 'product-list' (from DOM) or undefined
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export interface Action<K extends keyof ActionRecord = keyof ActionRecord> {
|
|
71
|
+
/**
|
|
72
|
+
* Unique action identifier — must be a key of `ActionRecord`.
|
|
73
|
+
*
|
|
74
|
+
* @example 'cart:add-item', 'open_drawer', 'logout'
|
|
75
|
+
*/
|
|
76
|
+
readonly type: K;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The DOM context in which the action was triggered.
|
|
80
|
+
*
|
|
81
|
+
* Extracted at delegation time from the nearest ancestor element that carries
|
|
82
|
+
* an `action-context` attribute. Useful for scoping the same action type to
|
|
83
|
+
* different UI regions (e.g. two sliders on the same page both dispatching
|
|
84
|
+
* `'slider:change'` but with different context values).
|
|
85
|
+
*
|
|
86
|
+
* `undefined` when the action is dispatched programmatically (no DOM involved)
|
|
87
|
+
* or when no `[action-context]` ancestor exists.
|
|
88
|
+
*
|
|
89
|
+
* @example 'slider-123', 'product-list', 'checkout-form'
|
|
90
|
+
*/
|
|
91
|
+
readonly context?: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The pure business payload carried by this action.
|
|
95
|
+
*
|
|
96
|
+
* Type is inferred from `ActionRecord[K]` — the compiler enforces the correct
|
|
97
|
+
* shape at every call site. No manual generic annotation is needed.
|
|
98
|
+
*/
|
|
99
|
+
readonly payload: ActionRecord[K];
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Open-ended metadata bag for cross-cutting concerns.
|
|
103
|
+
*
|
|
104
|
+
* Intentionally untyped so that future infrastructure layers (tracing,
|
|
105
|
+
* analytics, A/B testing) can attach data without touching the typed API.
|
|
106
|
+
* Modifiers in the delegation pipeline may also write to `meta` before the
|
|
107
|
+
* action reaches subscribers.
|
|
108
|
+
*
|
|
109
|
+
* Treat values here as `unknown` and validate before use.
|
|
110
|
+
*
|
|
111
|
+
* @example {traceId: 'abc-123', timestamp: Date.now()}
|
|
112
|
+
*/
|
|
113
|
+
meta?: DictionaryOpt<unknown>;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* A modifier handler used in `on-<eventType>` attribute syntax.
|
|
118
|
+
*
|
|
119
|
+
* Receives the triggering DOM `event`, the `element` that owns the
|
|
120
|
+
* `on-<eventType>` attribute, and the **mutable** `action` object being built.
|
|
121
|
+
* The handler may mutate `action.meta` to attach cross-cutting data (e.g. a
|
|
122
|
+
* trace ID, a timestamp, or an A/B flag) before the action reaches subscribers.
|
|
123
|
+
*
|
|
124
|
+
* Return `true` (or any truthy value) to allow the action to proceed, or
|
|
125
|
+
* `false` to cancel the dispatch entirely.
|
|
126
|
+
*
|
|
127
|
+
* Using explicit parameters instead of `this` binding makes handlers
|
|
128
|
+
* compatible with arrow functions and easier to test in isolation.
|
|
129
|
+
*
|
|
130
|
+
* @example — a modifier that stamps a timestamp into meta
|
|
131
|
+
* ```ts
|
|
132
|
+
* const timestampHandler: ModifierHandler = (_event, _element, action) => {
|
|
133
|
+
* action.meta ??= {};
|
|
134
|
+
* action.meta['timestamp'] = Date.now();
|
|
135
|
+
* return true;
|
|
136
|
+
* };
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @example — a modifier that cancels dispatch when the element is disabled
|
|
140
|
+
* ```ts
|
|
141
|
+
* const notDisabledHandler: ModifierHandler = (_event, element) => {
|
|
142
|
+
* return !(element as HTMLButtonElement).disabled;
|
|
143
|
+
* };
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export type ModifierHandler = (event: Event, element: HTMLElement, action: Action) => boolean;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* A payload resolver used in `on-<eventType>` attribute syntax.
|
|
150
|
+
*
|
|
151
|
+
* Receives the triggering DOM `event` and the `element` that owns the
|
|
152
|
+
* `on-<eventType>` attribute. The return value becomes the `payload` field of
|
|
153
|
+
* the `Action` object passed to `onAction` subscribers.
|
|
154
|
+
*
|
|
155
|
+
* Using explicit parameters instead of `this` binding makes resolvers
|
|
156
|
+
* compatible with arrow functions and easier to test in isolation.
|
|
157
|
+
*
|
|
158
|
+
* @example — a resolver that returns the element's dataset id
|
|
159
|
+
* ```ts
|
|
160
|
+
* const dataIdResolver: PayloadResolver = (_event, element) => {
|
|
161
|
+
* return (element as HTMLElement).dataset.id ?? null;
|
|
162
|
+
* };
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export type PayloadResolver = (event: Event, element: HTMLElement) => unknown;
|
package/dist/action-record.d.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
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
|
-
* This interface is intentionally empty in the base package — all actions are
|
|
37
|
-
* application-specific and should be declared in a dedicated `action-record.ts`
|
|
38
|
-
* file within each feature package.
|
|
39
|
-
*
|
|
40
|
-
* @example — registering actions in a feature package
|
|
41
|
-
* ```ts
|
|
42
|
-
* // pkg/my-feature/src/action-record.ts
|
|
43
|
-
* declare module '@alwatr/action' {
|
|
44
|
-
* interface ActionRecord {
|
|
45
|
-
* 'open_drawer': string;
|
|
46
|
-
* 'add_to_cart': {productId: number; qty: number};
|
|
47
|
-
* 'logout': void;
|
|
48
|
-
* }
|
|
49
|
-
* }
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
|
-
export interface ActionRecord {
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=action-record.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"action-record.d.ts","sourceRoot":"","sources":["../src/action-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,YAAY;CAAG"}
|
package/dist/lib.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,OAAO,uCAAgC,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,iEAAwE,CAAC"}
|
package/dist/registry.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A modifier handler used in `on-action` attribute syntax.
|
|
3
|
-
*
|
|
4
|
-
* Receives the triggering DOM `event` and the `element` that owns the
|
|
5
|
-
* `on-action` attribute. Return `true` (or any truthy value) to allow the
|
|
6
|
-
* action to proceed, or `false` to cancel the dispatch.
|
|
7
|
-
*
|
|
8
|
-
* Using explicit parameters instead of `this` binding makes handlers
|
|
9
|
-
* compatible with arrow functions and easier to test in isolation.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```ts
|
|
13
|
-
* // A modifier that only allows the action when the element is not disabled
|
|
14
|
-
* const notDisabledHandler: ModifierHandler = (_event, element) => {
|
|
15
|
-
* return !(element as HTMLButtonElement).disabled;
|
|
16
|
-
* };
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
export type ModifierHandler = (event: Event, element: HTMLElement) => boolean;
|
|
20
|
-
/**
|
|
21
|
-
* A payload resolver used in `on-action` attribute syntax.
|
|
22
|
-
*
|
|
23
|
-
* Receives the triggering DOM `event` and the `element` that owns the
|
|
24
|
-
* `on-action` attribute. The return value becomes the `actionPayload` passed
|
|
25
|
-
* to `onAction` subscribers. Use this to compute dynamic payloads from DOM state.
|
|
26
|
-
*
|
|
27
|
-
* Using explicit parameters instead of `this` binding makes resolvers
|
|
28
|
-
* compatible with arrow functions and easier to test in isolation.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```ts
|
|
32
|
-
* // A resolver that returns the element's dataset id
|
|
33
|
-
* const dataIdResolver: PayloadResolver = (_event, element) => {
|
|
34
|
-
* return (element as HTMLElement).dataset.id ?? null;
|
|
35
|
-
* };
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export type PayloadResolver = (event: Event, element: HTMLElement) => unknown;
|
|
39
|
-
/**
|
|
40
|
-
* Registry of all named modifier handlers.
|
|
41
|
-
*
|
|
42
|
-
* Keys are modifier names used in the `on-<eventType>` attribute syntax
|
|
43
|
-
* (e.g. `on-click="action-id; prevent"`). Values are `ModifierHandler` functions.
|
|
44
|
-
* Populated at module load with built-in modifiers; extended at runtime via
|
|
45
|
-
* `registerModifier`.
|
|
46
|
-
*
|
|
47
|
-
* @internal
|
|
48
|
-
*/
|
|
49
|
-
export declare const modifierRegistry: Map<string, ModifierHandler>;
|
|
50
|
-
/**
|
|
51
|
-
* Registry of all named payload resolvers.
|
|
52
|
-
*
|
|
53
|
-
* Keys are resolver tokens used in the `on-<eventType>` attribute syntax
|
|
54
|
-
* (e.g. `on-input="search_query:$value"`). Values are `PayloadResolver` functions.
|
|
55
|
-
* Populated at module load with built-in resolvers; extended at runtime via
|
|
56
|
-
* `registerPayloadResolver`.
|
|
57
|
-
*
|
|
58
|
-
* @internal
|
|
59
|
-
*/
|
|
60
|
-
export declare const payloadRegistry: Map<string, PayloadResolver>;
|
|
61
|
-
//# sourceMappingURL=registry.d.ts.map
|
package/dist/registry.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC;AAI9E;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,8BAAqC,CAAC;AAEnE;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,8BAAqC,CAAC"}
|
package/src/action-record.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
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
|
-
/**
|
|
32
|
-
* Global registry mapping action identifiers to their payload types.
|
|
33
|
-
*
|
|
34
|
-
* Extend this interface via declaration merging to register your application's
|
|
35
|
-
* actions and gain full type safety in `onAction` and `dispatchAction`.
|
|
36
|
-
*
|
|
37
|
-
* This interface is intentionally empty in the base package — all actions are
|
|
38
|
-
* application-specific and should be declared in a dedicated `action-record.ts`
|
|
39
|
-
* file within each feature package.
|
|
40
|
-
*
|
|
41
|
-
* @example — registering actions in a feature package
|
|
42
|
-
* ```ts
|
|
43
|
-
* // pkg/my-feature/src/action-record.ts
|
|
44
|
-
* declare module '@alwatr/action' {
|
|
45
|
-
* interface ActionRecord {
|
|
46
|
-
* 'open_drawer': string;
|
|
47
|
-
* 'add_to_cart': {productId: number; qty: number};
|
|
48
|
-
* 'logout': void;
|
|
49
|
-
* }
|
|
50
|
-
* }
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
54
|
-
export interface ActionRecord {}
|