@alwatr/action 9.28.0 → 9.29.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.
@@ -1,15 +1,6 @@
1
1
  import type { SubscribeResult } from '@alwatr/signal';
2
2
  import type { Awaitable } from '@alwatr/type-helper';
3
- import type { Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver } from './type.js';
4
- /**
5
- * Parsed representation of an action attribute descriptor.
6
- * @internal
7
- */
8
- interface ActionDescriptor {
9
- readonly modifiers: ReadonlySet<string>;
10
- readonly actionId: string;
11
- readonly payload: string | undefined;
12
- }
3
+ import type { Action, ActionDescriptor, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver } from './type.js';
13
4
  /**
14
5
  * Service to manage declarative DOM actions, programmatic dispatch,
15
6
  * modifiers, payload resolvers, and global event delegation.
@@ -174,5 +165,4 @@ export declare class ActionService {
174
165
  * ```
175
166
  */
176
167
  export declare const actionService: ActionService;
177
- export {};
178
168
  //# sourceMappingURL=action-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"action-service.d.ts","sourceRoot":"","sources":["../src/action-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAW,MAAM,qBAAqB,CAAC;AAE7D,OAAO,KAAK,EAAC,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAC,MAAM,WAAW,CAAC;AAErG;;;GAGG;AACH,UAAU,gBAAgB;IACxB,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAQD;;;;;;;;;;GAUG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,wBAAwB,EAAE,SAAS,MAAM,EAAE,CAA0C;IAErG,SAAS,CAAC,QAAQ,CAAC,OAAO,wCAAkC;IAE5D;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,wEAAyE;IAE5G;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,iBAAiB,+BAAsC;IAE1E;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,+BAAsC;IAEzE;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,uCAA8C;IAEjF;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,oBAAoB,cAAqB;IAE5D;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAyC;;IAOrF;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,GAAG,eAAe;IAuBjH;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI;IAKtE;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAS9D;;;;;;;;;;;;OAYG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI;IAStE;;;;;;;;;OASG;IACH,eAAe,CAAC,UAAU,GAAE,SAAS,MAAM,EAA2C,GAAG,IAAI;IAc7F;;;;;;;OAOG;IACH,kBAAkB,IAAI,IAAI;IAY1B;;;OAGG;IACH,SAAS,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAuB3E;;;OAGG;IACH,SAAS,CAAC,qBAAqB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAkFnD;;;OAGG;IACH,OAAO,CAAC,sCAAsC;CA6B/C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,eAAsB,CAAC"}
1
+ {"version":3,"file":"action-service.d.ts","sourceRoot":"","sources":["../src/action-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAW,MAAM,qBAAqB,CAAC;AAE7D,OAAO,KAAK,EAAC,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAC,MAAM,WAAW,CAAC;AAQvH;;;;;;;;;;GAUG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,wBAAwB,EAAE,SAAS,MAAM,EAAE,CAA0C;IAErG,SAAS,CAAC,QAAQ,CAAC,OAAO,wCAAkC;IAE5D;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,wEAAyE;IAE5G;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,iBAAiB,+BAAsC;IAE1E;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,+BAAsC;IAEzE;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,uCAA8C;IAEjF;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,oBAAoB,cAAqB;IAE5D;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAyC;;IAOrF;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,GAAG,eAAe;IAuBjH;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI;IAKtE;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAS9D;;;;;;;;;;;;OAYG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI;IAStE;;;;;;;;;OASG;IACH,eAAe,CAAC,UAAU,GAAE,SAAS,MAAM,EAA2C,GAAG,IAAI;IAc7F;;;;;;;OAOG;IACH,kBAAkB,IAAI,IAAI;IAY1B;;;OAGG;IACH,SAAS,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAuB3E;;;OAGG;IACH,SAAS,CAAC,qBAAqB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAkFnD;;;OAGG;IACH,OAAO,CAAC,sCAAsC;CA6B/C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,eAAsB,CAAC"}
package/dist/main.d.ts CHANGED
@@ -1,124 +1,3 @@
1
- import type { SubscribeResult } from '@alwatr/signal';
2
- import type { Awaitable } from '@alwatr/type-helper';
3
- import { actionService, ActionService } from './action-service.js';
4
- import type { Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver } from './type.js';
5
- export { actionService, ActionService };
6
- export type { Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver };
7
- /**
8
- * Default DOM event types that cover the vast majority of interactive elements.
9
- *
10
- * - `click` — buttons, links, checkboxes, custom interactive elements
11
- * - `submit` — form submission
12
- * - `input` — live text input, range sliders
13
- * - `change` — select boxes, checkboxes, radio buttons (fires on commit)
14
- */
15
- export declare const DEFAULT_DELEGATED_EVENTS: readonly string[];
16
- /**
17
- * Subscribes to a named action dispatched anywhere in the application.
18
- *
19
- * @template K - A key of ActionRecord.
20
- * @param type - Action type or array of action types to subscribe to.
21
- * @param handler - Callback invoked with the full Action object.
22
- * @returns SubscribeResult containing an `unsubscribe` method.
23
- *
24
- * @example
25
- * ```ts
26
- * import {onAction} from '@alwatr/action';
27
- *
28
- * // Subscribe to multiple action types
29
- * const sub = onAction(['ui_open_drawer', 'ui_close_drawer'], (action) => {
30
- * console.log(action.type, action.payload);
31
- * });
32
- * sub.unsubscribe();
33
- * ```
34
- *
35
- * @deprecated Use `actionService.on` instead.
36
- */
37
- export declare function onAction<K extends keyof ActionRecord>(type: K | K[], handler: (action: Action<K>) => Awaitable<void>): SubscribeResult;
38
- /**
39
- * Dispatches an action to all subscribers matching `action.type`.
40
- *
41
- * @template K - A key of ActionRecord.
42
- * @param action - Action object containing `type` and `payload`.
43
- *
44
- * @example
45
- * ```ts
46
- * import {dispatchAction} from '@alwatr/action';
47
- *
48
- * // Dispatches a typed action (payload is required)
49
- * dispatchAction({type: 'upload_complete', payload: 'file-123'});
50
- *
51
- * // Dispatches a void action (payload can be omitted)
52
- * dispatchAction({type: 'auth_expired'});
53
- * ```
54
- *
55
- * @deprecated Use `actionService.dispatch` instead.
56
- */
57
- export declare function dispatchAction<K extends keyof ActionRecord>(action: DispatchParam<K>): void;
58
- /**
59
- * Registers global event delegation listeners on `document.body`.
60
- *
61
- * @param eventTypes - List of event types to delegate. Defaults to DEFAULT_DELEGATED_EVENTS.
62
- *
63
- * @example
64
- * ```ts
65
- * import {setupActionDelegation} from '@alwatr/action';
66
- *
67
- * setupActionDelegation();
68
- * ```
69
- *
70
- * @deprecated Use `actionService.setupDelegation` instead.
71
- */
72
- export declare function setupActionDelegation(eventTypes?: readonly string[]): void;
73
- /**
74
- * Unregisters all global event delegation listeners.
75
- *
76
- * @example
77
- * ```ts
78
- * import {teardownActionDelegation} from '@alwatr/action';
79
- *
80
- * teardownActionDelegation();
81
- * ```
82
- *
83
- * @deprecated Use `actionService.teardownDelegation` instead.
84
- */
85
- export declare function teardownActionDelegation(): void;
86
- /**
87
- * Registers a custom modifier to enrich or filter actions before dispatch.
88
- *
89
- * @param name - Modifier name (lowercase, alphanumeric).
90
- * @param handler - Function called when modifier is invoked.
91
- *
92
- * @example
93
- * ```ts
94
- * import {registerModifier} from '@alwatr/action';
95
- *
96
- * registerModifier('trace', (_event, _element, action) => {
97
- * action.meta ??= {};
98
- * action.meta['time'] = Date.now();
99
- * return true;
100
- * });
101
- * ```
102
- *
103
- * @deprecated Use `actionService.registerModifier` instead.
104
- */
105
- export declare function registerModifier(name: string, handler: ModifierHandler): void;
106
- /**
107
- * Registers a custom payload resolver to map DOM state to action payload.
108
- *
109
- * @param name - Resolver token (by convention starting with `$`).
110
- * @param resolver - Function yielding payload from the event and element.
111
- *
112
- * @example
113
- * ```ts
114
- * import {registerPayloadResolver} from '@alwatr/action';
115
- *
116
- * registerPayloadResolver('$data-id', (_event, element) => {
117
- * return element.dataset.id;
118
- * });
119
- * ```
120
- *
121
- * @deprecated Use `actionService.registerPayloadResolver` instead.
122
- */
123
- export declare function registerPayloadResolver(name: string, resolver: PayloadResolver): void;
1
+ export * from './action-service.js';
2
+ export * from './type.js';
124
3
  //# sourceMappingURL=main.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAC,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAC,MAAM,WAAW,CAAC;AAErG,OAAO,EAAC,aAAa,EAAE,aAAa,EAAC,CAAC;AACtC,YAAY,EAAC,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAC,CAAC;AAEpF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,mBAAyC,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,YAAY,EACnD,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,EACb,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,GAC9C,eAAe,CAEjB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAE3F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAE1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAE7E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAErF"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC"}
package/dist/main.js CHANGED
@@ -1,5 +1,5 @@
1
- /* 📦 @alwatr/action v9.28.0 */
2
- import{createLogger as k}from"@alwatr/logger";import{createChannelSignal as F}from"@alwatr/signal";var I=/^(ui_[a-z0-9_-]+)(?::([^;]+))?(?:;\s*([a-z0-9_,-]+))?$/;class X{static DEFAULT_DELEGATED_EVENTS=["click","submit","input","change"];logger_=k("action-service");internalChannel_=F({name:"action-service"});modifierRegistry_=new Map;payloadRegistry_=new Map;descriptorCache_=new Map;delegatedEventTypes_=new Set;handleDelegatedEventBound__=this.handleDelegatedEvent_.bind(this);constructor(){this.logger_.logMethod?.("constructor"),this.registerDefaultModifiersAndResolvers__()}on(q,z){if(this.logger_.logMethodArgs?.("on",{type:q}),Array.isArray(q)){let B=q,J=[];for(let G of B)J.push(this.internalChannel_.on(G,z).unsubscribe);return{unsubscribe:()=>{this.logger_.logMethod?.("unsubscribe");for(let G of J)G();J.length=0}}}return this.internalChannel_.on(q,z)}dispatch(q){this.logger_.logMethodArgs?.("dispatch",q),this.internalChannel_.dispatch(q.type,q)}registerModifier(q,z){if(this.logger_.logMethodArgs?.("registerModifier",{name:q}),this.modifierRegistry_.has(q)){this.logger_.accident("registerModifier","modifier_already_registered",{name:q});return}this.modifierRegistry_.set(q,z)}registerPayloadResolver(q,z){if(this.logger_.logMethodArgs?.("registerPayloadResolver",{name:q}),this.payloadRegistry_.has(q)){this.logger_.accident("registerPayloadResolver","payload_resolver_already_registered",{name:q});return}this.payloadRegistry_.set(q,z)}setupDelegation(q=X.DEFAULT_DELEGATED_EVENTS){if(this.logger_.logMethodArgs?.("setupDelegation",{eventTypes:q}),typeof document>"u"||!document.body){this.logger_.incident?.("setupDelegation","document_body_not_found");return}for(let z of q){if(this.delegatedEventTypes_.has(z))continue;this.delegatedEventTypes_.add(z),document.body.addEventListener(z,this.handleDelegatedEventBound__,{capture:!0})}}teardownDelegation(){if(this.logger_.logMethod?.("teardownDelegation"),typeof document>"u"||!document.body)return;for(let q of this.delegatedEventTypes_)document.body.removeEventListener(q,this.handleDelegatedEventBound__,{capture:!0});this.delegatedEventTypes_.clear(),this.descriptorCache_.clear()}parseDescriptor_(q){this.logger_.logMethodArgs?.("parseDescriptor_",{attributeValue:q});let z=this.descriptorCache_.get(q);if(z!==void 0)return z;let B=q.match(I);if(!B)return this.logger_.accident("parseDescriptor_","invalid_syntax",{attributeValue:q}),this.descriptorCache_.set(q,null),null;let J=B[1],G=B[2],Q=B[3],Y={modifiers:Q?new Set(Q.split(",").filter(Boolean)):new Set,actionId:J,payload:G};return this.descriptorCache_.set(q,Y),Y}handleDelegatedEvent_(q){let z=q.type;this.logger_.logMethodArgs?.("handleDelegatedEvent_",{eventType:z});let B=q.target;if(!B)return;let J=`on-${z}`,G=B.closest?.(`[${J}]`);if(!G)return;let Q=G.getAttribute?.(J)?.trim();if(!Q){this.logger_.accident("handleDelegatedEvent_","empty_attribute",{eventType:z,actionElement:G});return}if(!(G instanceof HTMLElement)){this.logger_.accident("handleDelegatedEvent_","target_not_html_element",{eventType:z,actionElement:G});return}let H=this.parseDescriptor_(Q);if(!H)return;if(this.logger_.logMethodArgs?.("handleDelegatedEvent_.action",{eventType:z,descriptor:H}),H.modifiers.has("once"))G.removeAttribute(J);let Y=G.closest("[action-context]")?.getAttribute("action-context")??void 0,W={type:H.actionId,context:Y,payload:H.payload};for(let K of H.modifiers){if(K==="once")continue;let Z=this.modifierRegistry_.get(K);if(!Z){this.logger_.accident("handleDelegatedEvent_","unknown_modifier",{eventType:z,modifier:K,attributeValue:Q,descriptor:H});return}try{if(Z(q,G,W)===!1)return}catch(j){this.logger_.accident("handleDelegatedEvent_","modifier_execution_failed",{modifier:K,error:j});return}}if(H.payload){let K=this.payloadRegistry_.get(H.payload);if(K)try{W.payload=K(q,G)}catch(Z){this.logger_.accident("handleDelegatedEvent_","payload_resolver_failed",{resolver:H.payload,error:Z});return}}else W.payload=void 0;this.internalChannel_.dispatch(W.type,W)}registerDefaultModifiersAndResolvers__(){this.logger_.logMethod?.("registerDefaultModifiersAndResolvers__"),this.registerModifier("prevent",(q)=>{return q.preventDefault(),!0}),this.registerModifier("validate",(q,z)=>{let B=z instanceof HTMLFormElement?z:z.closest("form");if(!B)return!1;return B.checkValidity()}),this.registerPayloadResolver("$value",(q,z)=>{return"value"in z?z.value:null}),this.registerPayloadResolver("$formdata",(q,z)=>{let B=z instanceof HTMLFormElement?z:z.closest("form");return B?Object.fromEntries(new FormData(B)):null}),this.registerPayloadResolver("$checked",(q,z)=>{return"checked"in z?z.checked:null})}}var N=new X;var D=X.DEFAULT_DELEGATED_EVENTS;function _(q,z){return N.on(q,z)}function $(q){N.dispatch(q)}function P(q){N.setupDelegation(q)}function w(){N.teardownDelegation()}function x(q,z){N.registerModifier(q,z)}function L(q,z){N.registerPayloadResolver(q,z)}export{w as teardownActionDelegation,P as setupActionDelegation,L as registerPayloadResolver,x as registerModifier,_ as onAction,$ as dispatchAction,N as actionService,D as DEFAULT_DELEGATED_EVENTS,X as ActionService};
1
+ /* 📦 @alwatr/action v9.29.0 */
2
+ import{createLogger as P}from"@alwatr/logger";import{createChannelSignal as Q}from"@alwatr/signal";var U=/^(ui_[a-z0-9_-]+)(?::([^;]+))?(?:;\s*([a-z0-9_,-]+))?$/;class N{static DEFAULT_DELEGATED_EVENTS=["click","submit","input","change"];logger_=P("action-service");internalChannel_=Q({name:"action-service"});modifierRegistry_=new Map;payloadRegistry_=new Map;descriptorCache_=new Map;delegatedEventTypes_=new Set;handleDelegatedEventBound__=this.handleDelegatedEvent_.bind(this);constructor(){this.logger_.logMethod?.("constructor"),this.registerDefaultModifiersAndResolvers__()}on(j,k){if(this.logger_.logMethodArgs?.("on",{type:j}),Array.isArray(j)){let q=j,F=[];for(let z of q)F.push(this.internalChannel_.on(z,k).unsubscribe);return{unsubscribe:()=>{this.logger_.logMethod?.("unsubscribe");for(let z of F)z();F.length=0}}}return this.internalChannel_.on(j,k)}dispatch(j){this.logger_.logMethodArgs?.("dispatch",j),this.internalChannel_.dispatch(j.type,j)}registerModifier(j,k){if(this.logger_.logMethodArgs?.("registerModifier",{name:j}),this.modifierRegistry_.has(j)){this.logger_.accident("registerModifier","modifier_already_registered",{name:j});return}this.modifierRegistry_.set(j,k)}registerPayloadResolver(j,k){if(this.logger_.logMethodArgs?.("registerPayloadResolver",{name:j}),this.payloadRegistry_.has(j)){this.logger_.accident("registerPayloadResolver","payload_resolver_already_registered",{name:j});return}this.payloadRegistry_.set(j,k)}setupDelegation(j=N.DEFAULT_DELEGATED_EVENTS){if(this.logger_.logMethodArgs?.("setupDelegation",{eventTypes:j}),typeof document>"u"||!document.body){this.logger_.incident?.("setupDelegation","document_body_not_found");return}for(let k of j){if(this.delegatedEventTypes_.has(k))continue;this.delegatedEventTypes_.add(k),document.body.addEventListener(k,this.handleDelegatedEventBound__,{capture:!0})}}teardownDelegation(){if(this.logger_.logMethod?.("teardownDelegation"),typeof document>"u"||!document.body)return;for(let j of this.delegatedEventTypes_)document.body.removeEventListener(j,this.handleDelegatedEventBound__,{capture:!0});this.delegatedEventTypes_.clear(),this.descriptorCache_.clear()}parseDescriptor_(j){this.logger_.logMethodArgs?.("parseDescriptor_",{attributeValue:j});let k=this.descriptorCache_.get(j);if(k!==void 0)return k;let q=j.match(U);if(!q)return this.logger_.accident("parseDescriptor_","invalid_syntax",{attributeValue:j}),this.descriptorCache_.set(j,null),null;let F=q[1],z=q[2],H=q[3],K={modifiers:H?new Set(H.split(",").filter(Boolean)):new Set,actionId:F,payload:z};return this.descriptorCache_.set(j,K),K}handleDelegatedEvent_(j){let k=j.type;this.logger_.logMethodArgs?.("handleDelegatedEvent_",{eventType:k});let q=j.target;if(!q)return;let F=`on-${k}`,z=q.closest?.(`[${F}]`);if(!z)return;let H=z.getAttribute?.(F)?.trim();if(!H){this.logger_.accident("handleDelegatedEvent_","empty_attribute",{eventType:k,actionElement:z});return}if(!(z instanceof HTMLElement)){this.logger_.accident("handleDelegatedEvent_","target_not_html_element",{eventType:k,actionElement:z});return}let B=this.parseDescriptor_(H);if(!B)return;if(this.logger_.logMethodArgs?.("handleDelegatedEvent_.action",{eventType:k,descriptor:B}),B.modifiers.has("once"))z.removeAttribute(F);let K=z.closest("[action-context]")?.getAttribute("action-context")??void 0,J={type:B.actionId,context:K,payload:B.payload};for(let G of B.modifiers){if(G==="once")continue;let M=this.modifierRegistry_.get(G);if(!M){this.logger_.accident("handleDelegatedEvent_","unknown_modifier",{eventType:k,modifier:G,attributeValue:H,descriptor:B});return}try{if(M(j,z,J)===!1)return}catch(O){this.logger_.accident("handleDelegatedEvent_","modifier_execution_failed",{modifier:G,error:O});return}}if(B.payload){let G=this.payloadRegistry_.get(B.payload);if(G)try{J.payload=G(j,z)}catch(M){this.logger_.accident("handleDelegatedEvent_","payload_resolver_failed",{resolver:B.payload,error:M});return}}else J.payload=void 0;this.internalChannel_.dispatch(J.type,J)}registerDefaultModifiersAndResolvers__(){this.logger_.logMethod?.("registerDefaultModifiersAndResolvers__"),this.registerModifier("prevent",(j)=>{return j.preventDefault(),!0}),this.registerModifier("validate",(j,k)=>{let q=k instanceof HTMLFormElement?k:k.closest("form");if(!q)return!1;return q.checkValidity()}),this.registerPayloadResolver("$value",(j,k)=>{return"value"in k?k.value:null}),this.registerPayloadResolver("$formdata",(j,k)=>{let q=k instanceof HTMLFormElement?k:k.closest("form");return q?Object.fromEntries(new FormData(q)):null}),this.registerPayloadResolver("$checked",(j,k)=>{return"checked"in k?k.checked:null})}}var Y=new N;export{Y as actionService,N as ActionService};
3
3
 
4
- //# debugId=4D2180C09EEB93E964756E2164756E21
4
+ //# debugId=6745D692C7B93AB664756E2164756E21
5
5
  //# sourceMappingURL=main.js.map
package/dist/main.js.map CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/action-service.ts", "../src/main.ts"],
3
+ "sources": ["../src/action-service.ts"],
4
4
  "sourcesContent": [
5
- "import {createLogger} from '@alwatr/logger';\nimport {createChannelSignal} from '@alwatr/signal';\nimport type {SubscribeResult} from '@alwatr/signal';\nimport type {Awaitable, VoidFunc} from '@alwatr/type-helper';\n\nimport type {Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver} from './type.js';\n\n/**\n * Parsed representation of an action attribute descriptor.\n * @internal\n */\ninterface ActionDescriptor {\n readonly modifiers: ReadonlySet<string>;\n readonly actionId: string;\n readonly payload: string | undefined;\n}\n\n/**\n * Regex parser for the `on-<eventType>` attribute syntax.\n * Syntax: `actionId[:payload][; modifier1,modifier2,...]`\n */\nconst syntaxRegex = /^(ui_[a-z0-9_-]+)(?::([^;]+))?(?:;\\s*([a-z0-9_,-]+))?$/;\n\n/**\n * Service to manage declarative DOM actions, programmatic dispatch,\n * modifiers, payload resolvers, and global event delegation.\n *\n * @example\n * ```ts\n * import {ActionService} from '@alwatr/action';\n *\n * const customActionService = new ActionService();\n * ```\n */\nexport class ActionService {\n /**\n * Default DOM event types that cover the vast majority of interactive elements.\n */\n static readonly DEFAULT_DELEGATED_EVENTS: readonly string[] = ['click', 'submit', 'input', 'change'];\n\n protected readonly logger_ = createLogger('action-service');\n\n /**\n * Internal ChannelSignal used for routing dispatched actions.\n * @protected\n */\n protected readonly internalChannel_ = createChannelSignal<Record<string, Action>>({name: 'action-service'});\n\n /**\n * Registry mapping custom modifiers to their handlers.\n * @protected\n */\n protected readonly modifierRegistry_ = new Map<string, ModifierHandler>();\n\n /**\n * Registry mapping custom payload resolvers to their functions.\n * @protected\n */\n protected readonly payloadRegistry_ = new Map<string, PayloadResolver>();\n\n /**\n * Cache of parsed action descriptors to prevent redundant regex evaluation.\n * @protected\n */\n protected readonly descriptorCache_ = new Map<string, ActionDescriptor | null>();\n\n /**\n * Tracked event types currently delegated to `document.body`.\n * @protected\n */\n protected readonly delegatedEventTypes_ = new Set<string>();\n\n /**\n * Bound delegation handler for add/removeEventListener.\n * @private\n */\n private readonly handleDelegatedEventBound__ = this.handleDelegatedEvent_.bind(this);\n\n constructor() {\n this.logger_.logMethod?.('constructor');\n this.registerDefaultModifiersAndResolvers__();\n }\n\n /**\n * Subscribes to a named action dispatched anywhere in the application.\n *\n * @template K - A key of ActionRecord.\n * @param type - Action type or array of action types to subscribe to.\n * @param handler - Callback invoked with the full Action object.\n * @returns SubscribeResult containing an `unsubscribe` method.\n *\n * @example\n * ```ts\n * // Subscribe to a single action\n * const sub1 = actionService.on('ui_open_drawer', (action) => {\n * console.log(action.payload);\n * });\n *\n * // Subscribe to multiple action types\n * const sub2 = actionService.on(['ui_open_drawer', 'ui_close_drawer'], (action) => {\n * console.log(action.type, action.payload);\n * });\n * ```\n */\n on<K extends keyof ActionRecord>(type: K | K[], handler: (action: Action<K>) => Awaitable<void>): SubscribeResult {\n this.logger_.logMethodArgs?.('on', {type});\n if (Array.isArray(type)) {\n const typeList = type as K[];\n const unsubscribeList: VoidFunc[] = [];\n for (const type_ of typeList) {\n unsubscribeList.push(\n this.internalChannel_.on(type_, handler as (action: Action) => Awaitable<void>).unsubscribe,\n );\n }\n return {\n unsubscribe: () => {\n this.logger_.logMethod?.('unsubscribe');\n for (const unsubscribe of unsubscribeList) {\n unsubscribe();\n }\n unsubscribeList.length = 0;\n },\n };\n }\n return this.internalChannel_.on(type, handler as (action: Action) => Awaitable<void>);\n }\n\n /**\n * Dispatches an action to all subscribers matching `action.type`.\n *\n * @template K - A key of ActionRecord.\n * @param action - Action object containing `type` and `payload`.\n *\n * @example\n * ```ts\n * // Dispatches a typed action (payload is required)\n * actionService.dispatch({type: 'upload_complete', payload: 'file-123'});\n *\n * // Dispatches a void action (payload can be omitted)\n * actionService.dispatch({type: 'auth_expired'});\n * ```\n */\n dispatch<K extends keyof ActionRecord>(action: DispatchParam<K>): void {\n this.logger_.logMethodArgs?.('dispatch', action);\n this.internalChannel_.dispatch(action.type, action as Action<K>);\n }\n\n /**\n * Registers a custom modifier to enrich or filter actions before dispatch.\n *\n * @param name - Modifier name (lowercase, alphanumeric).\n * @param handler - Function called when modifier is invoked.\n *\n * @example\n * ```ts\n * actionService.registerModifier('trace', (_event, _element, action) => {\n * action.meta ??= {};\n * action.meta['time'] = Date.now();\n * return true;\n * });\n * ```\n */\n registerModifier(name: string, handler: ModifierHandler): void {\n this.logger_.logMethodArgs?.('registerModifier', {name});\n if (this.modifierRegistry_.has(name)) {\n this.logger_.accident('registerModifier', 'modifier_already_registered', {name});\n return;\n }\n this.modifierRegistry_.set(name, handler);\n }\n\n /**\n * Registers a custom payload resolver to map DOM state to action payload.\n *\n * @param name - Resolver token (by convention starting with `$`).\n * @param resolver - Function yielding payload from the event and element.\n *\n * @example\n * ```ts\n * actionService.registerPayloadResolver('$data-id', (_event, element) => {\n * return element.dataset.id;\n * });\n * ```\n */\n registerPayloadResolver(name: string, resolver: PayloadResolver): void {\n this.logger_.logMethodArgs?.('registerPayloadResolver', {name});\n if (this.payloadRegistry_.has(name)) {\n this.logger_.accident('registerPayloadResolver', 'payload_resolver_already_registered', {name});\n return;\n }\n this.payloadRegistry_.set(name, resolver);\n }\n\n /**\n * Registers global event delegation listeners on `document.body`.\n *\n * @param eventTypes - List of event types to delegate. Defaults to ActionService.DEFAULT_DELEGATED_EVENTS.\n *\n * @example\n * ```ts\n * actionService.setupDelegation();\n * ```\n */\n setupDelegation(eventTypes: readonly string[] = ActionService.DEFAULT_DELEGATED_EVENTS): void {\n this.logger_.logMethodArgs?.('setupDelegation', {eventTypes});\n if (typeof document === 'undefined' || !document.body) {\n this.logger_.incident?.('setupDelegation', 'document_body_not_found');\n return;\n }\n\n for (const eventType of eventTypes) {\n if (this.delegatedEventTypes_.has(eventType)) continue;\n this.delegatedEventTypes_.add(eventType);\n document.body.addEventListener(eventType, this.handleDelegatedEventBound__, {capture: true});\n }\n }\n\n /**\n * Unregisters all global event delegation listeners.\n *\n * @example\n * ```ts\n * actionService.teardownDelegation();\n * ```\n */\n teardownDelegation(): void {\n this.logger_.logMethod?.('teardownDelegation');\n if (typeof document === 'undefined' || !document.body) {\n return;\n }\n for (const eventType of this.delegatedEventTypes_) {\n document.body.removeEventListener(eventType, this.handleDelegatedEventBound__, {capture: true});\n }\n this.delegatedEventTypes_.clear();\n this.descriptorCache_.clear();\n }\n\n /**\n * Parses attribute values into action descriptor, utilizing the internal cache.\n * @protected\n */\n protected parseDescriptor_(attributeValue: string): ActionDescriptor | null {\n this.logger_.logMethodArgs?.('parseDescriptor_', {attributeValue});\n\n const cached = this.descriptorCache_.get(attributeValue);\n if (cached !== undefined) return cached;\n\n const match = attributeValue.match(syntaxRegex);\n if (!match) {\n this.logger_.accident('parseDescriptor_', 'invalid_syntax', {attributeValue});\n this.descriptorCache_.set(attributeValue, null);\n return null;\n }\n\n const actionId = match[1]!;\n const payload = match[2];\n const modifierString = match[3];\n const modifiers = modifierString ? new Set(modifierString.split(',').filter(Boolean)) : new Set<string>();\n\n const descriptor: ActionDescriptor = {modifiers, actionId, payload};\n this.descriptorCache_.set(attributeValue, descriptor);\n return descriptor;\n }\n\n /**\n * Global event delegation handler.\n * @protected\n */\n protected handleDelegatedEvent_(event: Event): void {\n const eventType = event.type;\n this.logger_.logMethodArgs?.('handleDelegatedEvent_', {eventType});\n\n const target = event.target as Element | null;\n if (!target) return;\n\n const actionAttrib = `on-${eventType}`;\n const actionElement = target.closest?.(`[${actionAttrib}]`);\n if (!actionElement) return;\n\n const attributeValue = actionElement.getAttribute?.(actionAttrib)?.trim();\n if (!attributeValue) {\n this.logger_.accident('handleDelegatedEvent_', 'empty_attribute', {eventType, actionElement});\n return;\n }\n\n if (!(actionElement instanceof HTMLElement)) {\n this.logger_.accident('handleDelegatedEvent_', 'target_not_html_element', {eventType, actionElement});\n return;\n }\n\n const descriptor = this.parseDescriptor_(attributeValue);\n if (!descriptor) return;\n\n this.logger_.logMethodArgs?.('handleDelegatedEvent_.action', {eventType, descriptor});\n\n if (descriptor.modifiers.has('once')) {\n actionElement.removeAttribute(actionAttrib);\n }\n\n const actionContext = actionElement.closest('[action-context]')?.getAttribute('action-context') ?? undefined;\n\n const action: Action = {\n type: descriptor.actionId as keyof ActionRecord,\n context: actionContext,\n payload: descriptor.payload as ActionRecord[keyof ActionRecord],\n };\n\n for (const modifier of descriptor.modifiers) {\n if (modifier === 'once') continue;\n const handler = this.modifierRegistry_.get(modifier);\n if (!handler) {\n this.logger_.accident('handleDelegatedEvent_', 'unknown_modifier', {\n eventType,\n modifier,\n attributeValue,\n descriptor,\n });\n return;\n }\n try {\n if (handler(event, actionElement, action) === false) return;\n } catch (error) {\n this.logger_.accident('handleDelegatedEvent_', 'modifier_execution_failed', {\n modifier,\n error,\n });\n return;\n }\n }\n\n if (descriptor.payload) {\n const resolver = this.payloadRegistry_.get(descriptor.payload);\n if (resolver) {\n try {\n (action as {payload: unknown}).payload = resolver(event, actionElement);\n } catch (error) {\n this.logger_.accident('handleDelegatedEvent_', 'payload_resolver_failed', {\n resolver: descriptor.payload,\n error,\n });\n return;\n }\n }\n } else {\n (action as {payload: unknown}).payload = undefined;\n }\n\n this.internalChannel_.dispatch(action.type, action);\n }\n\n /**\n * Registers default modifiers and resolvers.\n * @private\n */\n private registerDefaultModifiersAndResolvers__(): void {\n this.logger_.logMethod?.('registerDefaultModifiersAndResolvers__');\n\n // Built-in modifiers\n this.registerModifier('prevent', (event) => {\n event.preventDefault();\n return true;\n });\n\n this.registerModifier('validate', (_event, element) => {\n const form = element instanceof HTMLFormElement ? element : element.closest('form');\n if (!form) return false;\n return form.checkValidity();\n });\n\n // Built-in resolvers\n this.registerPayloadResolver('$value', (_event, element) => {\n return 'value' in element ? (element as {value: unknown}).value : null;\n });\n\n this.registerPayloadResolver('$formdata', (_event, element) => {\n const form = element instanceof HTMLFormElement ? element : element.closest('form');\n return form ? Object.fromEntries(new FormData(form)) : null;\n });\n\n this.registerPayloadResolver('$checked', (_event, element) => {\n return 'checked' in element ? (element as HTMLInputElement).checked : null;\n });\n }\n}\n\n/**\n * Singleton instance of the ActionService.\n * Ready for immediate use.\n *\n * @example\n * ```ts\n * import {actionService} from '@alwatr/action';\n *\n * actionService.setupDelegation();\n * ```\n */\nexport const actionService = new ActionService();\n",
6
- "import type {SubscribeResult} from '@alwatr/signal';\nimport type {Awaitable} from '@alwatr/type-helper';\n\nimport {actionService, ActionService} from './action-service.js';\nimport type {Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver} from './type.js';\n\nexport {actionService, ActionService};\nexport type {Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver};\n\n/**\n * Default DOM event types that cover the vast majority of interactive elements.\n *\n * - `click` — buttons, links, checkboxes, custom interactive elements\n * - `submit` — form submission\n * - `input` — live text input, range sliders\n * - `change` — select boxes, checkboxes, radio buttons (fires on commit)\n */\nexport const DEFAULT_DELEGATED_EVENTS = ActionService.DEFAULT_DELEGATED_EVENTS;\n\n/**\n * Subscribes to a named action dispatched anywhere in the application.\n *\n * @template K - A key of ActionRecord.\n * @param type - Action type or array of action types to subscribe to.\n * @param handler - Callback invoked with the full Action object.\n * @returns SubscribeResult containing an `unsubscribe` method.\n *\n * @example\n * ```ts\n * import {onAction} from '@alwatr/action';\n *\n * // Subscribe to multiple action types\n * const sub = onAction(['ui_open_drawer', 'ui_close_drawer'], (action) => {\n * console.log(action.type, action.payload);\n * });\n * sub.unsubscribe();\n * ```\n *\n * @deprecated Use `actionService.on` instead.\n */\nexport function onAction<K extends keyof ActionRecord>(\n type: K | K[],\n handler: (action: Action<K>) => Awaitable<void>,\n): SubscribeResult {\n return actionService.on(type, handler);\n}\n\n/**\n * Dispatches an action to all subscribers matching `action.type`.\n *\n * @template K - A key of ActionRecord.\n * @param action - Action object containing `type` and `payload`.\n *\n * @example\n * ```ts\n * import {dispatchAction} from '@alwatr/action';\n *\n * // Dispatches a typed action (payload is required)\n * dispatchAction({type: 'upload_complete', payload: 'file-123'});\n *\n * // Dispatches a void action (payload can be omitted)\n * dispatchAction({type: 'auth_expired'});\n * ```\n *\n * @deprecated Use `actionService.dispatch` instead.\n */\nexport function dispatchAction<K extends keyof ActionRecord>(action: DispatchParam<K>): void {\n actionService.dispatch(action);\n}\n\n/**\n * Registers global event delegation listeners on `document.body`.\n *\n * @param eventTypes - List of event types to delegate. Defaults to DEFAULT_DELEGATED_EVENTS.\n *\n * @example\n * ```ts\n * import {setupActionDelegation} from '@alwatr/action';\n *\n * setupActionDelegation();\n * ```\n *\n * @deprecated Use `actionService.setupDelegation` instead.\n */\nexport function setupActionDelegation(eventTypes?: readonly string[]): void {\n actionService.setupDelegation(eventTypes);\n}\n\n/**\n * Unregisters all global event delegation listeners.\n *\n * @example\n * ```ts\n * import {teardownActionDelegation} from '@alwatr/action';\n *\n * teardownActionDelegation();\n * ```\n *\n * @deprecated Use `actionService.teardownDelegation` instead.\n */\nexport function teardownActionDelegation(): void {\n actionService.teardownDelegation();\n}\n\n/**\n * Registers a custom modifier to enrich or filter actions before dispatch.\n *\n * @param name - Modifier name (lowercase, alphanumeric).\n * @param handler - Function called when modifier is invoked.\n *\n * @example\n * ```ts\n * import {registerModifier} from '@alwatr/action';\n *\n * registerModifier('trace', (_event, _element, action) => {\n * action.meta ??= {};\n * action.meta['time'] = Date.now();\n * return true;\n * });\n * ```\n *\n * @deprecated Use `actionService.registerModifier` instead.\n */\nexport function registerModifier(name: string, handler: ModifierHandler): void {\n actionService.registerModifier(name, handler);\n}\n\n/**\n * Registers a custom payload resolver to map DOM state to action payload.\n *\n * @param name - Resolver token (by convention starting with `$`).\n * @param resolver - Function yielding payload from the event and element.\n *\n * @example\n * ```ts\n * import {registerPayloadResolver} from '@alwatr/action';\n *\n * registerPayloadResolver('$data-id', (_event, element) => {\n * return element.dataset.id;\n * });\n * ```\n *\n * @deprecated Use `actionService.registerPayloadResolver` instead.\n */\nexport function registerPayloadResolver(name: string, resolver: PayloadResolver): void {\n actionService.registerPayloadResolver(name, resolver);\n}\n"
5
+ "import {createLogger} from '@alwatr/logger';\nimport {createChannelSignal} from '@alwatr/signal';\nimport type {SubscribeResult} from '@alwatr/signal';\nimport type {Awaitable, VoidFunc} from '@alwatr/type-helper';\n\nimport type {Action, ActionDescriptor, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver} from './type.js';\n\n/**\n * Regex parser for the `on-<eventType>` attribute syntax.\n * Syntax: `actionId[:payload][; modifier1,modifier2,...]`\n */\nconst syntaxRegex = /^(ui_[a-z0-9_-]+)(?::([^;]+))?(?:;\\s*([a-z0-9_,-]+))?$/;\n\n/**\n * Service to manage declarative DOM actions, programmatic dispatch,\n * modifiers, payload resolvers, and global event delegation.\n *\n * @example\n * ```ts\n * import {ActionService} from '@alwatr/action';\n *\n * const customActionService = new ActionService();\n * ```\n */\nexport class ActionService {\n /**\n * Default DOM event types that cover the vast majority of interactive elements.\n */\n static readonly DEFAULT_DELEGATED_EVENTS: readonly string[] = ['click', 'submit', 'input', 'change'];\n\n protected readonly logger_ = createLogger('action-service');\n\n /**\n * Internal ChannelSignal used for routing dispatched actions.\n * @protected\n */\n protected readonly internalChannel_ = createChannelSignal<Record<string, Action>>({name: 'action-service'});\n\n /**\n * Registry mapping custom modifiers to their handlers.\n * @protected\n */\n protected readonly modifierRegistry_ = new Map<string, ModifierHandler>();\n\n /**\n * Registry mapping custom payload resolvers to their functions.\n * @protected\n */\n protected readonly payloadRegistry_ = new Map<string, PayloadResolver>();\n\n /**\n * Cache of parsed action descriptors to prevent redundant regex evaluation.\n * @protected\n */\n protected readonly descriptorCache_ = new Map<string, ActionDescriptor | null>();\n\n /**\n * Tracked event types currently delegated to `document.body`.\n * @protected\n */\n protected readonly delegatedEventTypes_ = new Set<string>();\n\n /**\n * Bound delegation handler for add/removeEventListener.\n * @private\n */\n private readonly handleDelegatedEventBound__ = this.handleDelegatedEvent_.bind(this);\n\n constructor() {\n this.logger_.logMethod?.('constructor');\n this.registerDefaultModifiersAndResolvers__();\n }\n\n /**\n * Subscribes to a named action dispatched anywhere in the application.\n *\n * @template K - A key of ActionRecord.\n * @param type - Action type or array of action types to subscribe to.\n * @param handler - Callback invoked with the full Action object.\n * @returns SubscribeResult containing an `unsubscribe` method.\n *\n * @example\n * ```ts\n * // Subscribe to a single action\n * const sub1 = actionService.on('ui_open_drawer', (action) => {\n * console.log(action.payload);\n * });\n *\n * // Subscribe to multiple action types\n * const sub2 = actionService.on(['ui_open_drawer', 'ui_close_drawer'], (action) => {\n * console.log(action.type, action.payload);\n * });\n * ```\n */\n on<K extends keyof ActionRecord>(type: K | K[], handler: (action: Action<K>) => Awaitable<void>): SubscribeResult {\n this.logger_.logMethodArgs?.('on', {type});\n if (Array.isArray(type)) {\n const typeList = type as K[];\n const unsubscribeList: VoidFunc[] = [];\n for (const type_ of typeList) {\n unsubscribeList.push(\n this.internalChannel_.on(type_, handler as (action: Action) => Awaitable<void>).unsubscribe,\n );\n }\n return {\n unsubscribe: () => {\n this.logger_.logMethod?.('unsubscribe');\n for (const unsubscribe of unsubscribeList) {\n unsubscribe();\n }\n unsubscribeList.length = 0;\n },\n };\n }\n return this.internalChannel_.on(type, handler as (action: Action) => Awaitable<void>);\n }\n\n /**\n * Dispatches an action to all subscribers matching `action.type`.\n *\n * @template K - A key of ActionRecord.\n * @param action - Action object containing `type` and `payload`.\n *\n * @example\n * ```ts\n * // Dispatches a typed action (payload is required)\n * actionService.dispatch({type: 'upload_complete', payload: 'file-123'});\n *\n * // Dispatches a void action (payload can be omitted)\n * actionService.dispatch({type: 'auth_expired'});\n * ```\n */\n dispatch<K extends keyof ActionRecord>(action: DispatchParam<K>): void {\n this.logger_.logMethodArgs?.('dispatch', action);\n this.internalChannel_.dispatch(action.type, action as Action<K>);\n }\n\n /**\n * Registers a custom modifier to enrich or filter actions before dispatch.\n *\n * @param name - Modifier name (lowercase, alphanumeric).\n * @param handler - Function called when modifier is invoked.\n *\n * @example\n * ```ts\n * actionService.registerModifier('trace', (_event, _element, action) => {\n * action.meta ??= {};\n * action.meta['time'] = Date.now();\n * return true;\n * });\n * ```\n */\n registerModifier(name: string, handler: ModifierHandler): void {\n this.logger_.logMethodArgs?.('registerModifier', {name});\n if (this.modifierRegistry_.has(name)) {\n this.logger_.accident('registerModifier', 'modifier_already_registered', {name});\n return;\n }\n this.modifierRegistry_.set(name, handler);\n }\n\n /**\n * Registers a custom payload resolver to map DOM state to action payload.\n *\n * @param name - Resolver token (by convention starting with `$`).\n * @param resolver - Function yielding payload from the event and element.\n *\n * @example\n * ```ts\n * actionService.registerPayloadResolver('$data-id', (_event, element) => {\n * return element.dataset.id;\n * });\n * ```\n */\n registerPayloadResolver(name: string, resolver: PayloadResolver): void {\n this.logger_.logMethodArgs?.('registerPayloadResolver', {name});\n if (this.payloadRegistry_.has(name)) {\n this.logger_.accident('registerPayloadResolver', 'payload_resolver_already_registered', {name});\n return;\n }\n this.payloadRegistry_.set(name, resolver);\n }\n\n /**\n * Registers global event delegation listeners on `document.body`.\n *\n * @param eventTypes - List of event types to delegate. Defaults to ActionService.DEFAULT_DELEGATED_EVENTS.\n *\n * @example\n * ```ts\n * actionService.setupDelegation();\n * ```\n */\n setupDelegation(eventTypes: readonly string[] = ActionService.DEFAULT_DELEGATED_EVENTS): void {\n this.logger_.logMethodArgs?.('setupDelegation', {eventTypes});\n if (typeof document === 'undefined' || !document.body) {\n this.logger_.incident?.('setupDelegation', 'document_body_not_found');\n return;\n }\n\n for (const eventType of eventTypes) {\n if (this.delegatedEventTypes_.has(eventType)) continue;\n this.delegatedEventTypes_.add(eventType);\n document.body.addEventListener(eventType, this.handleDelegatedEventBound__, {capture: true});\n }\n }\n\n /**\n * Unregisters all global event delegation listeners.\n *\n * @example\n * ```ts\n * actionService.teardownDelegation();\n * ```\n */\n teardownDelegation(): void {\n this.logger_.logMethod?.('teardownDelegation');\n if (typeof document === 'undefined' || !document.body) {\n return;\n }\n for (const eventType of this.delegatedEventTypes_) {\n document.body.removeEventListener(eventType, this.handleDelegatedEventBound__, {capture: true});\n }\n this.delegatedEventTypes_.clear();\n this.descriptorCache_.clear();\n }\n\n /**\n * Parses attribute values into action descriptor, utilizing the internal cache.\n * @protected\n */\n protected parseDescriptor_(attributeValue: string): ActionDescriptor | null {\n this.logger_.logMethodArgs?.('parseDescriptor_', {attributeValue});\n\n const cached = this.descriptorCache_.get(attributeValue);\n if (cached !== undefined) return cached;\n\n const match = attributeValue.match(syntaxRegex);\n if (!match) {\n this.logger_.accident('parseDescriptor_', 'invalid_syntax', {attributeValue});\n this.descriptorCache_.set(attributeValue, null);\n return null;\n }\n\n const actionId = match[1]!;\n const payload = match[2];\n const modifierString = match[3];\n const modifiers = modifierString ? new Set(modifierString.split(',').filter(Boolean)) : new Set<string>();\n\n const descriptor: ActionDescriptor = {modifiers, actionId, payload};\n this.descriptorCache_.set(attributeValue, descriptor);\n return descriptor;\n }\n\n /**\n * Global event delegation handler.\n * @protected\n */\n protected handleDelegatedEvent_(event: Event): void {\n const eventType = event.type;\n this.logger_.logMethodArgs?.('handleDelegatedEvent_', {eventType});\n\n const target = event.target as Element | null;\n if (!target) return;\n\n const actionAttrib = `on-${eventType}`;\n const actionElement = target.closest?.(`[${actionAttrib}]`);\n if (!actionElement) return;\n\n const attributeValue = actionElement.getAttribute?.(actionAttrib)?.trim();\n if (!attributeValue) {\n this.logger_.accident('handleDelegatedEvent_', 'empty_attribute', {eventType, actionElement});\n return;\n }\n\n if (!(actionElement instanceof HTMLElement)) {\n this.logger_.accident('handleDelegatedEvent_', 'target_not_html_element', {eventType, actionElement});\n return;\n }\n\n const descriptor = this.parseDescriptor_(attributeValue);\n if (!descriptor) return;\n\n this.logger_.logMethodArgs?.('handleDelegatedEvent_.action', {eventType, descriptor});\n\n if (descriptor.modifiers.has('once')) {\n actionElement.removeAttribute(actionAttrib);\n }\n\n const actionContext = actionElement.closest('[action-context]')?.getAttribute('action-context') ?? undefined;\n\n const action: Action = {\n type: descriptor.actionId as keyof ActionRecord,\n context: actionContext,\n payload: descriptor.payload as ActionRecord[keyof ActionRecord],\n };\n\n for (const modifier of descriptor.modifiers) {\n if (modifier === 'once') continue;\n const handler = this.modifierRegistry_.get(modifier);\n if (!handler) {\n this.logger_.accident('handleDelegatedEvent_', 'unknown_modifier', {\n eventType,\n modifier,\n attributeValue,\n descriptor,\n });\n return;\n }\n try {\n if (handler(event, actionElement, action) === false) return;\n } catch (error) {\n this.logger_.accident('handleDelegatedEvent_', 'modifier_execution_failed', {\n modifier,\n error,\n });\n return;\n }\n }\n\n if (descriptor.payload) {\n const resolver = this.payloadRegistry_.get(descriptor.payload);\n if (resolver) {\n try {\n (action as {payload: unknown}).payload = resolver(event, actionElement);\n } catch (error) {\n this.logger_.accident('handleDelegatedEvent_', 'payload_resolver_failed', {\n resolver: descriptor.payload,\n error,\n });\n return;\n }\n }\n } else {\n (action as {payload: unknown}).payload = undefined;\n }\n\n this.internalChannel_.dispatch(action.type, action);\n }\n\n /**\n * Registers default modifiers and resolvers.\n * @private\n */\n private registerDefaultModifiersAndResolvers__(): void {\n this.logger_.logMethod?.('registerDefaultModifiersAndResolvers__');\n\n // Built-in modifiers\n this.registerModifier('prevent', (event) => {\n event.preventDefault();\n return true;\n });\n\n this.registerModifier('validate', (_event, element) => {\n const form = element instanceof HTMLFormElement ? element : element.closest('form');\n if (!form) return false;\n return form.checkValidity();\n });\n\n // Built-in resolvers\n this.registerPayloadResolver('$value', (_event, element) => {\n return 'value' in element ? (element as {value: unknown}).value : null;\n });\n\n this.registerPayloadResolver('$formdata', (_event, element) => {\n const form = element instanceof HTMLFormElement ? element : element.closest('form');\n return form ? Object.fromEntries(new FormData(form)) : null;\n });\n\n this.registerPayloadResolver('$checked', (_event, element) => {\n return 'checked' in element ? (element as HTMLInputElement).checked : null;\n });\n }\n}\n\n/**\n * Singleton instance of the ActionService.\n * Ready for immediate use.\n *\n * @example\n * ```ts\n * import {actionService} from '@alwatr/action';\n *\n * actionService.setupDelegation();\n * ```\n */\nexport const actionService = new ActionService();\n"
7
6
  ],
8
- "mappings": ";AAAA,uBAAQ,uBACR,8BAAQ,uBAoBR,IAAM,EAAc,yDAab,MAAM,CAAc,OAIT,0BAA8C,CAAC,QAAS,SAAU,QAAS,QAAQ,EAEhF,QAAU,EAAa,gBAAgB,EAMvC,iBAAmB,EAA4C,CAAC,KAAM,gBAAgB,CAAC,EAMvF,kBAAoB,IAAI,IAMxB,iBAAmB,IAAI,IAMvB,iBAAmB,IAAI,IAMvB,qBAAuB,IAAI,IAM7B,4BAA8B,KAAK,sBAAsB,KAAK,IAAI,EAEnF,WAAW,EAAG,CACZ,KAAK,QAAQ,YAAY,aAAa,EACtC,KAAK,uCAAuC,EAwB9C,EAAgC,CAAC,EAAe,EAAkE,CAEhH,GADA,KAAK,QAAQ,gBAAgB,KAAM,CAAC,MAAI,CAAC,EACrC,MAAM,QAAQ,CAAI,EAAG,CACvB,IAAM,EAAW,EACX,EAA8B,CAAC,EACrC,QAAW,KAAS,EAClB,EAAgB,KACd,KAAK,iBAAiB,GAAG,EAAO,CAA8C,EAAE,WAClF,EAEF,MAAO,CACL,YAAa,IAAM,CACjB,KAAK,QAAQ,YAAY,aAAa,EACtC,QAAW,KAAe,EACxB,EAAY,EAEd,EAAgB,OAAS,EAE7B,EAEF,OAAO,KAAK,iBAAiB,GAAG,EAAM,CAA8C,EAkBtF,QAAsC,CAAC,EAAgC,CACrE,KAAK,QAAQ,gBAAgB,WAAY,CAAM,EAC/C,KAAK,iBAAiB,SAAS,EAAO,KAAM,CAAmB,EAkBjE,gBAAgB,CAAC,EAAc,EAAgC,CAE7D,GADA,KAAK,QAAQ,gBAAgB,mBAAoB,CAAC,MAAI,CAAC,EACnD,KAAK,kBAAkB,IAAI,CAAI,EAAG,CACpC,KAAK,QAAQ,SAAS,mBAAoB,8BAA+B,CAAC,MAAI,CAAC,EAC/E,OAEF,KAAK,kBAAkB,IAAI,EAAM,CAAO,EAgB1C,uBAAuB,CAAC,EAAc,EAAiC,CAErE,GADA,KAAK,QAAQ,gBAAgB,0BAA2B,CAAC,MAAI,CAAC,EAC1D,KAAK,iBAAiB,IAAI,CAAI,EAAG,CACnC,KAAK,QAAQ,SAAS,0BAA2B,sCAAuC,CAAC,MAAI,CAAC,EAC9F,OAEF,KAAK,iBAAiB,IAAI,EAAM,CAAQ,EAa1C,eAAe,CAAC,EAAgC,EAAc,yBAAgC,CAE5F,GADA,KAAK,QAAQ,gBAAgB,kBAAmB,CAAC,YAAU,CAAC,EACxD,OAAO,SAAa,KAAe,CAAC,SAAS,KAAM,CACrD,KAAK,QAAQ,WAAW,kBAAmB,yBAAyB,EACpE,OAGF,QAAW,KAAa,EAAY,CAClC,GAAI,KAAK,qBAAqB,IAAI,CAAS,EAAG,SAC9C,KAAK,qBAAqB,IAAI,CAAS,EACvC,SAAS,KAAK,iBAAiB,EAAW,KAAK,4BAA6B,CAAC,QAAS,EAAI,CAAC,GAY/F,kBAAkB,EAAS,CAEzB,GADA,KAAK,QAAQ,YAAY,oBAAoB,EACzC,OAAO,SAAa,KAAe,CAAC,SAAS,KAC/C,OAEF,QAAW,KAAa,KAAK,qBAC3B,SAAS,KAAK,oBAAoB,EAAW,KAAK,4BAA6B,CAAC,QAAS,EAAI,CAAC,EAEhG,KAAK,qBAAqB,MAAM,EAChC,KAAK,iBAAiB,MAAM,EAOpB,gBAAgB,CAAC,EAAiD,CAC1E,KAAK,QAAQ,gBAAgB,mBAAoB,CAAC,gBAAc,CAAC,EAEjE,IAAM,EAAS,KAAK,iBAAiB,IAAI,CAAc,EACvD,GAAI,IAAW,OAAW,OAAO,EAEjC,IAAM,EAAQ,EAAe,MAAM,CAAW,EAC9C,GAAI,CAAC,EAGH,OAFA,KAAK,QAAQ,SAAS,mBAAoB,iBAAkB,CAAC,gBAAc,CAAC,EAC5E,KAAK,iBAAiB,IAAI,EAAgB,IAAI,EACvC,KAGT,IAAM,EAAW,EAAM,GACjB,EAAU,EAAM,GAChB,EAAiB,EAAM,GAGvB,EAA+B,CAAC,UAFpB,EAAiB,IAAI,IAAI,EAAe,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC,EAAI,IAAI,IAE3C,WAAU,SAAO,EAElE,OADA,KAAK,iBAAiB,IAAI,EAAgB,CAAU,EAC7C,EAOC,qBAAqB,CAAC,EAAoB,CAClD,IAAM,EAAY,EAAM,KACxB,KAAK,QAAQ,gBAAgB,wBAAyB,CAAC,WAAS,CAAC,EAEjE,IAAM,EAAS,EAAM,OACrB,GAAI,CAAC,EAAQ,OAEb,IAAM,EAAe,MAAM,IACrB,EAAgB,EAAO,UAAU,IAAI,IAAe,EAC1D,GAAI,CAAC,EAAe,OAEpB,IAAM,EAAiB,EAAc,eAAe,CAAY,GAAG,KAAK,EACxE,GAAI,CAAC,EAAgB,CACnB,KAAK,QAAQ,SAAS,wBAAyB,kBAAmB,CAAC,YAAW,eAAa,CAAC,EAC5F,OAGF,GAAI,EAAE,aAAyB,aAAc,CAC3C,KAAK,QAAQ,SAAS,wBAAyB,0BAA2B,CAAC,YAAW,eAAa,CAAC,EACpG,OAGF,IAAM,EAAa,KAAK,iBAAiB,CAAc,EACvD,GAAI,CAAC,EAAY,OAIjB,GAFA,KAAK,QAAQ,gBAAgB,+BAAgC,CAAC,YAAW,YAAU,CAAC,EAEhF,EAAW,UAAU,IAAI,MAAM,EACjC,EAAc,gBAAgB,CAAY,EAG5C,IAAM,EAAgB,EAAc,QAAQ,kBAAkB,GAAG,aAAa,gBAAgB,GAAK,OAE7F,EAAiB,CACrB,KAAM,EAAW,SACjB,QAAS,EACT,QAAS,EAAW,OACtB,EAEA,QAAW,KAAY,EAAW,UAAW,CAC3C,GAAI,IAAa,OAAQ,SACzB,IAAM,EAAU,KAAK,kBAAkB,IAAI,CAAQ,EACnD,GAAI,CAAC,EAAS,CACZ,KAAK,QAAQ,SAAS,wBAAyB,mBAAoB,CACjE,YACA,WACA,iBACA,YACF,CAAC,EACD,OAEF,GAAI,CACF,GAAI,EAAQ,EAAO,EAAe,CAAM,IAAM,GAAO,OACrD,MAAO,EAAO,CACd,KAAK,QAAQ,SAAS,wBAAyB,4BAA6B,CAC1E,WACA,OACF,CAAC,EACD,QAIJ,GAAI,EAAW,QAAS,CACtB,IAAM,EAAW,KAAK,iBAAiB,IAAI,EAAW,OAAO,EAC7D,GAAI,EACF,GAAI,CACD,EAA8B,QAAU,EAAS,EAAO,CAAa,EACtE,MAAO,EAAO,CACd,KAAK,QAAQ,SAAS,wBAAyB,0BAA2B,CACxE,SAAU,EAAW,QACrB,OACF,CAAC,EACD,QAIJ,KAAC,EAA8B,QAAU,OAG3C,KAAK,iBAAiB,SAAS,EAAO,KAAM,CAAM,EAO5C,sCAAsC,EAAS,CACrD,KAAK,QAAQ,YAAY,wCAAwC,EAGjE,KAAK,iBAAiB,UAAW,CAAC,IAAU,CAE1C,OADA,EAAM,eAAe,EACd,GACR,EAED,KAAK,iBAAiB,WAAY,CAAC,EAAQ,IAAY,CACrD,IAAM,EAAO,aAAmB,gBAAkB,EAAU,EAAQ,QAAQ,MAAM,EAClF,GAAI,CAAC,EAAM,MAAO,GAClB,OAAO,EAAK,cAAc,EAC3B,EAGD,KAAK,wBAAwB,SAAU,CAAC,EAAQ,IAAY,CAC1D,MAAO,UAAW,EAAW,EAA6B,MAAQ,KACnE,EAED,KAAK,wBAAwB,YAAa,CAAC,EAAQ,IAAY,CAC7D,IAAM,EAAO,aAAmB,gBAAkB,EAAU,EAAQ,QAAQ,MAAM,EAClF,OAAO,EAAO,OAAO,YAAY,IAAI,SAAS,CAAI,CAAC,EAAI,KACxD,EAED,KAAK,wBAAwB,WAAY,CAAC,EAAQ,IAAY,CAC5D,MAAO,YAAa,EAAW,EAA6B,QAAU,KACvE,EAEL,CAaO,IAAM,EAAgB,IAAI,EC3X1B,IAAM,EAA2B,EAAc,yBAuB/C,SAAS,CAAsC,CACpD,EACA,EACiB,CACjB,OAAO,EAAc,GAAG,EAAM,CAAO,EAsBhC,SAAS,CAA4C,CAAC,EAAgC,CAC3F,EAAc,SAAS,CAAM,EAiBxB,SAAS,CAAqB,CAAC,EAAsC,CAC1E,EAAc,gBAAgB,CAAU,EAenC,SAAS,CAAwB,EAAS,CAC/C,EAAc,mBAAmB,EAsB5B,SAAS,CAAgB,CAAC,EAAc,EAAgC,CAC7E,EAAc,iBAAiB,EAAM,CAAO,EAoBvC,SAAS,CAAuB,CAAC,EAAc,EAAiC,CACrF,EAAc,wBAAwB,EAAM,CAAQ",
9
- "debugId": "4D2180C09EEB93E964756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "6745D692C7B93AB664756E2164756E21",
10
9
  "names": []
11
10
  }
package/dist/type.d.ts CHANGED
@@ -162,4 +162,13 @@ export type ModifierHandler = (event: Event, element: HTMLElement, action: Actio
162
162
  * ```
163
163
  */
164
164
  export type PayloadResolver = (event: Event, element: HTMLElement) => unknown;
165
+ /**
166
+ * Parsed representation of an action attribute descriptor.
167
+ * @internal
168
+ */
169
+ export interface ActionDescriptor {
170
+ readonly modifiers: ReadonlySet<string>;
171
+ readonly actionId: string;
172
+ readonly payload: string | undefined;
173
+ }
165
174
  //# sourceMappingURL=type.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,YAAY;CAAG;AAEhC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,YAAY,IACpD,YAAY,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG;IAAC,OAAO,CAAC,EAAE,IAAI,CAAA;CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AAE3F;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,MAAM,CAAC,CAAC,SAAS,MAAM,YAAY,GAAG,MAAM,YAAY;IACvE;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAEjB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAElC;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;AAE9F;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC"}
1
+ {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,YAAY;CAAG;AAEhC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,YAAY,IACpD,YAAY,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG;IAAC,OAAO,CAAC,EAAE,IAAI,CAAA;CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AAE3F;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,MAAM,CAAC,CAAC,SAAS,MAAM,YAAY,GAAG,MAAM,YAAY;IACvE;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAEjB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAElC;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;AAE9F;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC;AAE9E;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alwatr/action",
3
- "version": "9.28.0",
3
+ "version": "9.29.0",
4
4
  "description": "Declarative DOM action-dispatch — bridge HTML attributes to typed signal handlers.",
5
5
  "license": "MPL-2.0",
6
6
  "author": "S. Ali Mihandoost <ali.mihandoost@gmail.com> (https://ali.mihandoost.com)",
@@ -21,8 +21,8 @@
21
21
  },
22
22
  "sideEffects": false,
23
23
  "dependencies": {
24
- "@alwatr/logger": "9.25.0",
25
- "@alwatr/signal": "9.26.0"
24
+ "@alwatr/logger": "9.29.0",
25
+ "@alwatr/signal": "9.29.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@alwatr/nano-build": "9.25.0",
@@ -80,5 +80,5 @@
80
80
  "vanilla-js",
81
81
  "web-development"
82
82
  ],
83
- "gitHead": "d60f1d986e5ff44f871d38231f1f2be60833140b"
83
+ "gitHead": "2f80c615d90e038dca634a2dfba8d900d3df6248"
84
84
  }
@@ -3,17 +3,7 @@ import {createChannelSignal} from '@alwatr/signal';
3
3
  import type {SubscribeResult} from '@alwatr/signal';
4
4
  import type {Awaitable, VoidFunc} from '@alwatr/type-helper';
5
5
 
6
- import type {Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver} from './type.js';
7
-
8
- /**
9
- * Parsed representation of an action attribute descriptor.
10
- * @internal
11
- */
12
- interface ActionDescriptor {
13
- readonly modifiers: ReadonlySet<string>;
14
- readonly actionId: string;
15
- readonly payload: string | undefined;
16
- }
6
+ import type {Action, ActionDescriptor, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver} from './type.js';
17
7
 
18
8
  /**
19
9
  * Regex parser for the `on-<eventType>` attribute syntax.
package/src/main.ts CHANGED
@@ -1,147 +1,2 @@
1
- import type {SubscribeResult} from '@alwatr/signal';
2
- import type {Awaitable} from '@alwatr/type-helper';
3
-
4
- import {actionService, ActionService} from './action-service.js';
5
- import type {Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver} from './type.js';
6
-
7
- export {actionService, ActionService};
8
- export type {Action, ActionRecord, DispatchParam, ModifierHandler, PayloadResolver};
9
-
10
- /**
11
- * Default DOM event types that cover the vast majority of interactive elements.
12
- *
13
- * - `click` — buttons, links, checkboxes, custom interactive elements
14
- * - `submit` — form submission
15
- * - `input` — live text input, range sliders
16
- * - `change` — select boxes, checkboxes, radio buttons (fires on commit)
17
- */
18
- export const DEFAULT_DELEGATED_EVENTS = ActionService.DEFAULT_DELEGATED_EVENTS;
19
-
20
- /**
21
- * Subscribes to a named action dispatched anywhere in the application.
22
- *
23
- * @template K - A key of ActionRecord.
24
- * @param type - Action type or array of action types to subscribe to.
25
- * @param handler - Callback invoked with the full Action object.
26
- * @returns SubscribeResult containing an `unsubscribe` method.
27
- *
28
- * @example
29
- * ```ts
30
- * import {onAction} from '@alwatr/action';
31
- *
32
- * // Subscribe to multiple action types
33
- * const sub = onAction(['ui_open_drawer', 'ui_close_drawer'], (action) => {
34
- * console.log(action.type, action.payload);
35
- * });
36
- * sub.unsubscribe();
37
- * ```
38
- *
39
- * @deprecated Use `actionService.on` instead.
40
- */
41
- export function onAction<K extends keyof ActionRecord>(
42
- type: K | K[],
43
- handler: (action: Action<K>) => Awaitable<void>,
44
- ): SubscribeResult {
45
- return actionService.on(type, handler);
46
- }
47
-
48
- /**
49
- * Dispatches an action to all subscribers matching `action.type`.
50
- *
51
- * @template K - A key of ActionRecord.
52
- * @param action - Action object containing `type` and `payload`.
53
- *
54
- * @example
55
- * ```ts
56
- * import {dispatchAction} from '@alwatr/action';
57
- *
58
- * // Dispatches a typed action (payload is required)
59
- * dispatchAction({type: 'upload_complete', payload: 'file-123'});
60
- *
61
- * // Dispatches a void action (payload can be omitted)
62
- * dispatchAction({type: 'auth_expired'});
63
- * ```
64
- *
65
- * @deprecated Use `actionService.dispatch` instead.
66
- */
67
- export function dispatchAction<K extends keyof ActionRecord>(action: DispatchParam<K>): void {
68
- actionService.dispatch(action);
69
- }
70
-
71
- /**
72
- * Registers global event delegation listeners on `document.body`.
73
- *
74
- * @param eventTypes - List of event types to delegate. Defaults to DEFAULT_DELEGATED_EVENTS.
75
- *
76
- * @example
77
- * ```ts
78
- * import {setupActionDelegation} from '@alwatr/action';
79
- *
80
- * setupActionDelegation();
81
- * ```
82
- *
83
- * @deprecated Use `actionService.setupDelegation` instead.
84
- */
85
- export function setupActionDelegation(eventTypes?: readonly string[]): void {
86
- actionService.setupDelegation(eventTypes);
87
- }
88
-
89
- /**
90
- * Unregisters all global event delegation listeners.
91
- *
92
- * @example
93
- * ```ts
94
- * import {teardownActionDelegation} from '@alwatr/action';
95
- *
96
- * teardownActionDelegation();
97
- * ```
98
- *
99
- * @deprecated Use `actionService.teardownDelegation` instead.
100
- */
101
- export function teardownActionDelegation(): void {
102
- actionService.teardownDelegation();
103
- }
104
-
105
- /**
106
- * Registers a custom modifier to enrich or filter actions before dispatch.
107
- *
108
- * @param name - Modifier name (lowercase, alphanumeric).
109
- * @param handler - Function called when modifier is invoked.
110
- *
111
- * @example
112
- * ```ts
113
- * import {registerModifier} from '@alwatr/action';
114
- *
115
- * registerModifier('trace', (_event, _element, action) => {
116
- * action.meta ??= {};
117
- * action.meta['time'] = Date.now();
118
- * return true;
119
- * });
120
- * ```
121
- *
122
- * @deprecated Use `actionService.registerModifier` instead.
123
- */
124
- export function registerModifier(name: string, handler: ModifierHandler): void {
125
- actionService.registerModifier(name, handler);
126
- }
127
-
128
- /**
129
- * Registers a custom payload resolver to map DOM state to action payload.
130
- *
131
- * @param name - Resolver token (by convention starting with `$`).
132
- * @param resolver - Function yielding payload from the event and element.
133
- *
134
- * @example
135
- * ```ts
136
- * import {registerPayloadResolver} from '@alwatr/action';
137
- *
138
- * registerPayloadResolver('$data-id', (_event, element) => {
139
- * return element.dataset.id;
140
- * });
141
- * ```
142
- *
143
- * @deprecated Use `actionService.registerPayloadResolver` instead.
144
- */
145
- export function registerPayloadResolver(name: string, resolver: PayloadResolver): void {
146
- actionService.registerPayloadResolver(name, resolver);
147
- }
1
+ export * from './action-service.js';
2
+ export * from './type.js';
package/src/type.ts CHANGED
@@ -168,3 +168,13 @@ export type ModifierHandler = (event: Event, element: HTMLElement, action: Actio
168
168
  * ```
169
169
  */
170
170
  export type PayloadResolver = (event: Event, element: HTMLElement) => unknown;
171
+
172
+ /**
173
+ * Parsed representation of an action attribute descriptor.
174
+ * @internal
175
+ */
176
+ export interface ActionDescriptor {
177
+ readonly modifiers: ReadonlySet<string>;
178
+ readonly actionId: string;
179
+ readonly payload: string | undefined;
180
+ }