@alwatr/flux 9.26.0 → 9.27.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 +47 -43
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -65,15 +65,15 @@ declare module '@alwatr/flux' {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// Get compile-time safety everywhere — handler receives the full Action object
|
|
68
|
-
|
|
68
|
+
actionService.on('ui_add_to_cart', (action) => {
|
|
69
69
|
// action.payload is typed as {productId: number; qty: number}
|
|
70
70
|
cartService.add(action.payload.productId, action.payload.qty);
|
|
71
71
|
// action.context is the nearest [action-context] ancestor value (or undefined)
|
|
72
72
|
console.log(action.context); // e.g. 'product-list'
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
actionService.dispatch({type: 'ui_add_to_cart', payload: {productId: 42, qty: 1}}); // ✅
|
|
76
|
+
actionService.dispatch({type: 'ui_add_to_cart', payload: 'wrong'}); // ❌ Compile error
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
---
|
|
@@ -173,7 +173,7 @@ Connect DOM events to typed actions without writing JavaScript. Wrap elements in
|
|
|
173
173
|
|
|
174
174
|
```typescript
|
|
175
175
|
// Handler receives the full Action object — payload, context, and meta together
|
|
176
|
-
|
|
176
|
+
actionService.on('ui_slider_change', (action) => {
|
|
177
177
|
if (action.context === 'volume') audioService.setVolume(Number(action.payload));
|
|
178
178
|
if (action.context === 'brightness') displayService.setBrightness(Number(action.payload));
|
|
179
179
|
});
|
|
@@ -406,13 +406,13 @@ Flux implements a **strict layered architecture** where each layer has a single
|
|
|
406
406
|
│ • Resolves payload ($value, $formdata) │
|
|
407
407
|
│ • Dispatches full Action {type, payload, context, meta} │
|
|
408
408
|
└──────────────────┬────────────────────────────────────────┘
|
|
409
|
-
│
|
|
409
|
+
│ actionService.dispatch({type: 'ui_add_to_cart', payload: 42, context: 'cart'})
|
|
410
410
|
▼
|
|
411
411
|
┌───────────────────────────────────────────────────────────┐
|
|
412
412
|
│ CONTROLLER LAYER │
|
|
413
413
|
│ (Business Logic, Services, Use Cases) │
|
|
414
414
|
│ │
|
|
415
|
-
│ • Subscribes to Actions via
|
|
415
|
+
│ • Subscribes to Actions via actionService.on() │
|
|
416
416
|
│ • Receives full Action object (type, payload, context, │
|
|
417
417
|
│ meta) — no need to pass context separately │
|
|
418
418
|
│ • Executes business logic │
|
|
@@ -480,7 +480,7 @@ interface Action<K extends keyof ActionRecord> {
|
|
|
480
480
|
This unified structure replaces the previous two-argument `(id, payload)` API. Every handler now receives the full picture:
|
|
481
481
|
|
|
482
482
|
```typescript
|
|
483
|
-
|
|
483
|
+
actionService.on('ui_add_to_cart', (action) => {
|
|
484
484
|
console.log(action.type); // 'ui_add_to_cart'
|
|
485
485
|
console.log(action.payload); // {productId: 42, qty: 1} — fully typed
|
|
486
486
|
console.log(action.context); // 'product-list' — from [action-context] ancestor
|
|
@@ -491,9 +491,9 @@ onAction('ui_add_to_cart', (action) => {
|
|
|
491
491
|
Modifiers can enrich `meta` before the action reaches subscribers:
|
|
492
492
|
|
|
493
493
|
```typescript
|
|
494
|
-
import {
|
|
494
|
+
import {actionService} from '@alwatr/flux';
|
|
495
495
|
|
|
496
|
-
registerModifier('trace', (_event, _element, action) => {
|
|
496
|
+
actionService.registerModifier('trace', (_event, _element, action) => {
|
|
497
497
|
action.meta ??= {};
|
|
498
498
|
action.meta['traceId'] = crypto.randomUUID();
|
|
499
499
|
return true;
|
|
@@ -531,10 +531,10 @@ bun add @alwatr/flux
|
|
|
531
531
|
### 1. Bootstrap the Application
|
|
532
532
|
|
|
533
533
|
```typescript
|
|
534
|
-
import {
|
|
534
|
+
import {actionService, dispatchPageReady} from '@alwatr/flux';
|
|
535
535
|
|
|
536
536
|
// Activate global event delegation (call once at app start)
|
|
537
|
-
|
|
537
|
+
actionService.setupDelegation();
|
|
538
538
|
|
|
539
539
|
// Dispatch page-ready signal (for MPA routing)
|
|
540
540
|
dispatchPageReady();
|
|
@@ -569,19 +569,19 @@ export const counterSignal = createStateSignal({
|
|
|
569
569
|
|
|
570
570
|
```typescript
|
|
571
571
|
// src/controllers.ts
|
|
572
|
-
import {
|
|
572
|
+
import {actionService} from '@alwatr/flux';
|
|
573
573
|
import {counterSignal} from './state.js';
|
|
574
574
|
|
|
575
|
-
|
|
575
|
+
actionService.on('ui_increment', () => {
|
|
576
576
|
counterSignal.update((count) => count + 1);
|
|
577
577
|
});
|
|
578
578
|
|
|
579
|
-
|
|
579
|
+
actionService.on('ui_decrement', () => {
|
|
580
580
|
counterSignal.update((count) => count - 1);
|
|
581
581
|
});
|
|
582
582
|
|
|
583
583
|
// Handler receives the full Action object — payload is typed from ActionRecord
|
|
584
|
-
|
|
584
|
+
actionService.on('ui_set_count', (action) => {
|
|
585
585
|
counterSignal.set(action.payload); // action.payload: number
|
|
586
586
|
});
|
|
587
587
|
```
|
|
@@ -616,11 +616,11 @@ onAction('ui_set_count', (action) => {
|
|
|
616
616
|
|
|
617
617
|
```typescript
|
|
618
618
|
// main.js
|
|
619
|
-
import {
|
|
619
|
+
import {actionService} from '@alwatr/flux';
|
|
620
620
|
import {counterSignal} from './state.js';
|
|
621
621
|
import './controllers.js'; // Register action handlers
|
|
622
622
|
|
|
623
|
-
|
|
623
|
+
actionService.setupDelegation();
|
|
624
624
|
|
|
625
625
|
// Subscribe to state changes and update DOM
|
|
626
626
|
counterSignal.subscribe((count) => {
|
|
@@ -736,34 +736,38 @@ const mapped = createMappedSignal(source, {
|
|
|
736
736
|
|
|
737
737
|
### Actions
|
|
738
738
|
|
|
739
|
-
#### `
|
|
739
|
+
#### `actionService`
|
|
740
740
|
|
|
741
|
-
|
|
741
|
+
The pre-instantiated singleton instance of `ActionService` exported for declarative event delegation and action dispatching.
|
|
742
|
+
|
|
743
|
+
##### `actionService.setupDelegation(eventTypes?)`
|
|
744
|
+
|
|
745
|
+
Activates global event delegation capture listeners on `document.body`.
|
|
742
746
|
|
|
743
747
|
```typescript
|
|
744
|
-
import {
|
|
748
|
+
import {actionService, DEFAULT_DELEGATED_EVENTS} from '@alwatr/flux';
|
|
745
749
|
|
|
746
750
|
// Use defaults (click, submit, input, change)
|
|
747
|
-
|
|
751
|
+
actionService.setupDelegation();
|
|
748
752
|
|
|
749
753
|
// Or add custom events
|
|
750
|
-
|
|
754
|
+
actionService.setupDelegation([...DEFAULT_DELEGATED_EVENTS, 'keydown', 'focus']);
|
|
751
755
|
```
|
|
752
756
|
|
|
753
|
-
|
|
757
|
+
##### `actionService.on(type, handler)`
|
|
754
758
|
|
|
755
|
-
Subscribes to a single typed action or an array of actions.
|
|
759
|
+
Subscribes to a single typed action or an array of actions.
|
|
756
760
|
|
|
757
761
|
```typescript
|
|
758
762
|
// Subscribe to a single action
|
|
759
|
-
const sub =
|
|
763
|
+
const sub = actionService.on('ui_add_to_cart', (action) => {
|
|
760
764
|
cartService.add(action.payload.productId, action.payload.qty);
|
|
761
765
|
console.log(action.context); // e.g. 'product-list' or undefined
|
|
762
766
|
console.log(action.meta); // any metadata set by modifiers
|
|
763
767
|
});
|
|
764
768
|
|
|
765
769
|
// Subscribe to multiple actions with a single handler
|
|
766
|
-
const multiSub =
|
|
770
|
+
const multiSub = actionService.on(['ui_increment', 'ui_decrement'], (action) => {
|
|
767
771
|
console.log('Action triggered:', action.type);
|
|
768
772
|
});
|
|
769
773
|
|
|
@@ -771,16 +775,16 @@ sub.unsubscribe(); // Clean up when done
|
|
|
771
775
|
multiSub.unsubscribe();
|
|
772
776
|
```
|
|
773
777
|
|
|
774
|
-
|
|
778
|
+
##### `actionService.dispatch(action)`
|
|
775
779
|
|
|
776
|
-
Dispatches a typed action programmatically.
|
|
780
|
+
Dispatches a typed action programmatically.
|
|
777
781
|
|
|
778
782
|
```typescript
|
|
779
|
-
|
|
780
|
-
|
|
783
|
+
actionService.dispatch({type: 'navigate', payload: '/home'});
|
|
784
|
+
actionService.dispatch({type: 'auth_expired', payload: undefined}); // void payload
|
|
781
785
|
|
|
782
786
|
// With context and meta
|
|
783
|
-
|
|
787
|
+
actionService.dispatch({
|
|
784
788
|
type: 'upload_complete',
|
|
785
789
|
payload: fileId,
|
|
786
790
|
context: 'product-list',
|
|
@@ -788,17 +792,17 @@ dispatchAction({
|
|
|
788
792
|
});
|
|
789
793
|
```
|
|
790
794
|
|
|
791
|
-
|
|
795
|
+
##### `actionService.registerModifier(name, handler)`
|
|
792
796
|
|
|
793
|
-
Adds a custom modifier for `on-<event>` attributes.
|
|
797
|
+
Adds a custom modifier for `on-<event>` attributes.
|
|
794
798
|
|
|
795
799
|
```typescript
|
|
796
|
-
registerModifier('confirm', () => {
|
|
800
|
+
actionService.registerModifier('confirm', () => {
|
|
797
801
|
return window.confirm('Are you sure?');
|
|
798
802
|
});
|
|
799
803
|
|
|
800
804
|
// A modifier that stamps a trace ID into meta
|
|
801
|
-
registerModifier('trace', (_event, _element, action) => {
|
|
805
|
+
actionService.registerModifier('trace', (_event, _element, action) => {
|
|
802
806
|
action.meta ??= {};
|
|
803
807
|
action.meta['traceId'] = crypto.randomUUID();
|
|
804
808
|
return true;
|
|
@@ -809,12 +813,12 @@ registerModifier('trace', (_event, _element, action) => {
|
|
|
809
813
|
<button on-click="ui_delete_item:42; confirm,trace">Delete</button>
|
|
810
814
|
```
|
|
811
815
|
|
|
812
|
-
|
|
816
|
+
##### `actionService.registerPayloadResolver(name, resolver)`
|
|
813
817
|
|
|
814
818
|
Adds a custom payload resolver.
|
|
815
819
|
|
|
816
820
|
```typescript
|
|
817
|
-
registerPayloadResolver('$data-id', (_event, element) => {
|
|
821
|
+
actionService.registerPayloadResolver('$data-id', (_event, element) => {
|
|
818
822
|
return element.dataset.id;
|
|
819
823
|
});
|
|
820
824
|
```
|
|
@@ -1238,19 +1242,19 @@ export const todosSignal = createStateSignal<Todo[]>({
|
|
|
1238
1242
|
});
|
|
1239
1243
|
|
|
1240
1244
|
// controllers.ts
|
|
1241
|
-
import {
|
|
1245
|
+
import {actionService} from '@alwatr/flux';
|
|
1242
1246
|
import {todosSignal} from './state.js';
|
|
1243
1247
|
|
|
1244
1248
|
let nextId = 1;
|
|
1245
1249
|
|
|
1246
|
-
|
|
1250
|
+
actionService.on('ui_add_todo', (action) => {
|
|
1247
1251
|
todosSignal.update((todos) => [
|
|
1248
1252
|
...todos,
|
|
1249
1253
|
{id: nextId++, text: action.payload, done: false},
|
|
1250
1254
|
]);
|
|
1251
1255
|
});
|
|
1252
1256
|
|
|
1253
|
-
|
|
1257
|
+
actionService.on('ui_toggle_todo', (action) => {
|
|
1254
1258
|
todosSignal.update((todos) =>
|
|
1255
1259
|
todos.map((todo) =>
|
|
1256
1260
|
todo.id === action.payload ? {...todo, done: !todo.done} : todo
|
|
@@ -1258,7 +1262,7 @@ onAction('ui_toggle_todo', (action) => {
|
|
|
1258
1262
|
);
|
|
1259
1263
|
});
|
|
1260
1264
|
|
|
1261
|
-
|
|
1265
|
+
actionService.on('ui_remove_todo', (action) => {
|
|
1262
1266
|
todosSignal.update((todos) => todos.filter((t) => t.id !== action.payload));
|
|
1263
1267
|
});
|
|
1264
1268
|
|
|
@@ -1269,11 +1273,11 @@ onAction('ui_remove_todo', (action) => {
|
|
|
1269
1273
|
</div>
|
|
1270
1274
|
|
|
1271
1275
|
// main.ts
|
|
1272
|
-
import {
|
|
1276
|
+
import {actionService, html, render} from '@alwatr/flux';
|
|
1273
1277
|
import {todosSignal} from './state.js';
|
|
1274
1278
|
import './controllers.js';
|
|
1275
1279
|
|
|
1276
|
-
|
|
1280
|
+
actionService.setupDelegation();
|
|
1277
1281
|
|
|
1278
1282
|
todosSignal.subscribe((todos) => {
|
|
1279
1283
|
render(
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/* 📦 @alwatr/flux v9.
|
|
1
|
+
/* 📦 @alwatr/flux v9.27.0 */
|
|
2
2
|
export*from"@alwatr/signal";export*from"@alwatr/action";export*from"@alwatr/directive";export*from"@alwatr/embedded-data";export*from"@alwatr/keyboard-shortcut";export*from"@alwatr/render-state";export*from"@alwatr/local-storage";export*from"@alwatr/session-storage";export*from"@alwatr/page-ready";import{html as e,svg as p,mathml as a,render as f,noChange as t,nothing as n}from"lit-html";import{unsafeSVG as g}from"lit-html/directives/unsafe-svg.js";import{ifDefined as i}from"lit-html/directives/if-defined.js";import{cache as s}from"lit-html/directives/cache.js";import{classMap as b}from"lit-html/directives/class-map.js";import{when as d}from"lit-html/directives/when.js";import{repeat as I}from"lit-html/directives/repeat.js";export{d as when,g as unsafeSVG,p as svg,I as repeat,f as render,n as nothing,t as noChange,a as mathml,i as ifDefined,e as html,b as classMap,s as cache};
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=48C4CA5B471A0B6264756E2164756E21
|
|
5
5
|
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
CHANGED
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
"/**\n * Curated re-exports from `lit-html` for use within `@alwatr/flux`.\n *\n * Only the subset of `lit-html` APIs that are commonly needed in a Flux-based\n * application is exported here. This keeps the public surface minimal and\n * avoids pulling in advanced directive utilities that most consumers never use.\n *\n * **Exported APIs:**\n * - `html` — tagged template literal that produces a `TemplateResult`\n * - `render` — renders a `TemplateResult` into a DOM container\n * - `noChange` — sentinel that tells lit-html to leave the current part value unchanged\n * - `nothing` — sentinel that renders nothing (removes the node/attribute)\n * - `ifDefined` — renders a value only when it is not `undefined`\n * - `cache` — caches rendered templates to avoid re-parsing on state changes\n * - `classMap` — efficiently sets/removes CSS classes from an object map\n * - `when` — conditional rendering helper (`when(condition, trueCase, falseCase)`)\n *\n * @example\n * ```typescript\n * import {html, render, classMap, when} from '@alwatr/flux';\n *\n * const template = (isActive: boolean) => html`\n * <div class=${classMap({active: isActive, hidden: !isActive})}>\n * ${when(isActive, () => html`<span>Active</span>`, () => html`<span>Inactive</span>`)}\n * </div>\n * `;\n *\n * render(template(true), document.getElementById('app')!);\n * ```\n */\nexport {\n html,\n svg,\n mathml,\n render,\n noChange,\n nothing,\n type TemplateResult,\n type HTMLTemplateResult,\n type SVGTemplateResult,\n type MathMLTemplateResult,\n} from 'lit-html';\nexport {unsafeSVG} from 'lit-html/directives/unsafe-svg.js';\nexport {ifDefined} from 'lit-html/directives/if-defined.js';\nexport {cache} from 'lit-html/directives/cache.js';\nexport {classMap, type ClassInfo} from 'lit-html/directives/class-map.js';\nexport {when} from 'lit-html/directives/when.js';\nexport {repeat, type RepeatDirectiveFn, type KeyFn, type ItemTemplate} from 'lit-html/directives/repeat.js';\n"
|
|
7
7
|
],
|
|
8
8
|
"mappings": ";AAGA,4BACA,4BACA,+BACA,mCACA,uCACA,kCACA,mCACA,qCACA,gCCmBA,eACE,SACA,YACA,YACA,cACA,aACA,iBAMF,oBAAQ,0CACR,oBAAQ,0CACR,gBAAQ,qCACR,mBAAQ,yCACR,eAAQ,oCACR,iBAAQ",
|
|
9
|
-
"debugId": "
|
|
9
|
+
"debugId": "48C4CA5B471A0B6264756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alwatr/flux",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.27.0",
|
|
4
4
|
"description": "UI and reactive library bundle for ECMAScript (JavaScript/TypeScript) projects — signals, actions, directives, and storage.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"author": "S. Ali Mihandoost <ali.mihandoost@gmail.com> (https://ali.mihandoost.com)",
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
},
|
|
22
22
|
"sideEffects": false,
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@alwatr/action": "9.
|
|
24
|
+
"@alwatr/action": "9.27.0",
|
|
25
25
|
"@alwatr/directive": "9.26.0",
|
|
26
26
|
"@alwatr/embedded-data": "9.25.0",
|
|
27
|
-
"@alwatr/keyboard-shortcut": "9.
|
|
27
|
+
"@alwatr/keyboard-shortcut": "9.27.0",
|
|
28
28
|
"@alwatr/local-storage": "9.25.0",
|
|
29
|
-
"@alwatr/page-ready": "9.
|
|
29
|
+
"@alwatr/page-ready": "9.27.0",
|
|
30
30
|
"@alwatr/render-state": "9.25.0",
|
|
31
31
|
"@alwatr/session-storage": "9.25.0",
|
|
32
32
|
"@alwatr/signal": "9.26.0",
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"ui",
|
|
85
85
|
"unidirectional-data-flow"
|
|
86
86
|
],
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "a5591e8230a1a33b5414297345ae5f6fd3e5a168"
|
|
88
88
|
}
|