@alwatr/flux 9.26.0 → 9.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -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
- onAction('ui_add_to_cart', (action) => {
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
- dispatchAction({type: 'ui_add_to_cart', payload: {productId: 42, qty: 1}}); // ✅
76
- dispatchAction({type: 'ui_add_to_cart', payload: 'wrong'}); // ❌ Compile error
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
- onAction('ui_slider_change', (action) => {
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
  });
@@ -377,12 +377,71 @@ createEffect({
377
377
  });
378
378
  ```
379
379
 
380
+ ### 🤖 **Finite State Machine (FSM) & Actor Model**
381
+
382
+ Flux natively aggregates `@alwatr/fsm` to eliminate ad-hoc state variables, boolean flags, and race conditions. Instead of writing unpredictable, disjointed spaghetti code, you model your application's lifecycle as a **declarative, type-safe statechart**.
383
+
384
+ ```typescript
385
+ import {createFsmService} from '@alwatr/flux';
386
+ import type {StateMachineConfig} from '@alwatr/flux';
387
+
388
+ // 1. Define strict Union Types for compile-time safety
389
+ type FetchState = 'idle' | 'loading' | 'success' | 'failed';
390
+ type FetchEvent = {type: 'FETCH'} | {type: 'SUCCESS'} | {type: 'ERROR'};
391
+ interface FetchContext { retries: number }
392
+
393
+ // 2. Configure the machine declaratively
394
+ const fetchConfig: StateMachineConfig<FetchState, FetchEvent, FetchContext> = {
395
+ name: 'api-fetch-lifecycle',
396
+ initial: 'idle',
397
+ context: {retries: 0},
398
+ states: {
399
+ idle: {
400
+ on: { FETCH: { target: 'loading' } },
401
+ },
402
+ loading: {
403
+ on: {
404
+ SUCCESS: { target: 'success', assigners: [({context}) => ({...context, retries: 0})] },
405
+ ERROR: [
406
+ // Guard evaluates condition; first matching transition branch is chosen
407
+ { target: 'loading', guard: ({context}) => context.retries < 3, assigners: [({context}) => ({...context, retries: context.retries + 1})] },
408
+ { target: 'failed' }
409
+ ],
410
+ },
411
+ },
412
+ success: {},
413
+ failed: {
414
+ on: { FETCH: { target: 'loading', assigners: [({context}) => ({...context, retries: 0})] } },
415
+ },
416
+ },
417
+ };
418
+
419
+ // 3. Create the reactive service (FSM Service instance)
420
+ export const fetchService = createFsmService(fetchConfig);
421
+
422
+ // 4. Surgical Reactivity: Subscribe to state changes in the view layer
423
+ fetchService.stateSignal.subscribe((state) => {
424
+ console.log(`Current State: ${state.name}, Retries: ${state.context.retries}`);
425
+ });
426
+
427
+ // 5. Dispatch events to trigger atomic transitions
428
+ fetchService.dispatch({type: 'FETCH'});
429
+ ```
430
+
431
+ #### 🛡️ Why is Flux FSM a Game-Changer?
432
+
433
+ - **Eliminates Race Conditions (Run-to-Completion)**: FSM events are queued and processed sequentially. Async callbacks from concurrent network fetches never overwrite or corrupt the state.
434
+ - **Prevents State Explosion**: Ad-hoc booleans (like `isLoading`, `isError`, `hasFetched`) scale exponentially (e.g., 5 booleans = 32 states). FSM forces you to define a finite set of **valid states and transitions** (e.g., exactly 4 states).
435
+ - **Embedded Actor Architecture**: Statecharts can spawn long-running, asynchronous, isolated lifecycles called **Actors** on state entry, complete with auto-cleanup on exit.
436
+ - **Declarative Synergy**: The FSM's internal `stateSignal` integrates flawlessly with the `@alwatr/flux` unidirectional loop, feeding directly into your rendering template.
437
+
380
438
  ---
381
439
 
382
440
  ## 🏗️ Architecture Overview
383
441
 
384
- Flux implements a **strict layered architecture** where each layer has a single responsibility:
442
+ Flux implements a **strict layered architecture** where each layer has a single responsibility. It supports both standard Unidirectional Data Flow (UDF) and the decentralized **Actor Model** (where components/features behave as isolated micro-services powered by FSMs).
385
443
 
444
+ ### 1. Unidirectional Data Flow (UDF) Layering
386
445
  ```
387
446
  ┌───────────────────────────────────────────────────────────┐
388
447
  │ VIEW LAYER │
@@ -406,13 +465,13 @@ Flux implements a **strict layered architecture** where each layer has a single
406
465
  │ • Resolves payload ($value, $formdata) │
407
466
  │ • Dispatches full Action {type, payload, context, meta} │
408
467
  └──────────────────┬────────────────────────────────────────┘
409
- dispatchAction({type: 'ui_add_to_cart', payload: 42, context: 'cart'})
468
+ actionService.dispatch({type: 'ui_add_to_cart', payload: 42, context: 'cart'})
410
469
 
411
470
  ┌───────────────────────────────────────────────────────────┐
412
471
  │ CONTROLLER LAYER │
413
472
  │ (Business Logic, Services, Use Cases) │
414
473
  │ │
415
- │ • Subscribes to Actions via onAction()
474
+ │ • Subscribes to Actions via actionService.on()
416
475
  │ • Receives full Action object (type, payload, context, │
417
476
  │ meta) — no need to pass context separately │
418
477
  │ • Executes business logic │
@@ -439,13 +498,68 @@ Flux implements a **strict layered architecture** where each layer has a single
439
498
  └───────────────────────────────────────────────────────────┘
440
499
  ```
441
500
 
501
+ ### 2. Decoupled Actor Model Flow
502
+
503
+ In complex applications, you can structure features as **Actors** using `@alwatr/fsm` + `@alwatr/action`. An Actor maintains private local state, receives inbound event packets from the global action bus, and broadcasts changes asynchronously back to the ecosystem.
504
+
505
+ ```mermaid
506
+ graph TD
507
+ %% Styling
508
+ classDef view fill:#E1F5FE,stroke:#03A9F4,stroke-width:2px,color:#01579B;
509
+ classDef action fill:#FFF3E0,stroke:#FF9800,stroke-width:2px,color:#E65100;
510
+ classDef fsm fill:#E8F5E9,stroke:#4CAF50,stroke-width:2px,color:#1B5E20;
511
+ classDef actor fill:#F3E5F5,stroke:#9C27B0,stroke-width:2px,color:#4A148C;
512
+ classDef global fill:#ECEFF1,stroke:#607D8B,stroke-width:2px,color:#263238;
513
+
514
+ subgraph View ["View Layer (lit-html & Directives)"]
515
+ V[DOM / UI Elements]
516
+ end
517
+
518
+ subgraph Actions ["Action Bus (Global Delegation)"]
519
+ AB[actionService.dispatch]
520
+ end
521
+
522
+ subgraph Controllers ["Actor Controller Layer"]
523
+ C[Input Controller / Message Router]
524
+ end
525
+
526
+ subgraph ActorDomain ["Decoupled Actor (FSM Brain)"]
527
+ direction TB
528
+ FSM[FsmService]
529
+ Ctx[(Extended Context)]
530
+ Actors[Spawning State Actors]
531
+ end
532
+
533
+ subgraph State ["Reactive State Layer (Signals)"]
534
+ SS[stateSignal]
535
+ end
536
+
537
+ %% Flow
538
+ V -->|on-click / on-input| AB
539
+ AB -->|Global AFSA Message| C
540
+ C -->|dispatch Event| FSM
541
+ FSM -->|1. Run-to-Completion| Ctx
542
+ FSM -->|2. Entry/Exit Effects| Actors
543
+ FSM -->|3. Update State| SS
544
+ SS -->|Re-render / Update UI| V
545
+ Actors -.->|Asynchronous Events| AB
546
+
547
+ %% Apply Classes
548
+ class V view;
549
+ class AB action;
550
+ class C global;
551
+ class FSM,Ctx fsm;
552
+ class Actors actor;
553
+ class SS view;
554
+ ```
555
+
442
556
  **Key architectural benefits:**
443
557
 
444
- - **Zero coupling** — layers communicate only through well-defined interfaces
445
- - **Testability** — each layer can be tested in isolation
446
- - **Scalability** — add features without touching existing code
447
- - **Predictability** — data flows in one direction only
448
- - **Performance** — fine-grained updates, no full-tree reconciliation
558
+ - **Zero coupling** — layers and actors communicate only through events, guaranteeing that features can be refactored, extended, or replaced without side effects.
559
+ - **Run-to-Completion (RTC)** — State machines evaluate transitions atomically in a synchronous queue. Race conditions are mathematically impossible.
560
+ - **High Testability** — Since business logic is isolated inside declarative statecharts (`StateMachineConfig`), you can test all transitions and side-effects in node/bun without mounting a DOM.
561
+ - **Surgical Reactivity** — Only the DOM elements bound to the FSM's `stateSignal` or Context properties re-render, keeping CPU usage and memory footprints exceptionally low.
562
+ - **AI-Agent and Developer Friendly** — The explicit separation of routing, transition, and effect layers provides clean boundaries that humans and AI agents can navigate with zero ambiguity.
449
563
 
450
564
  ---
451
565
 
@@ -480,7 +594,7 @@ interface Action<K extends keyof ActionRecord> {
480
594
  This unified structure replaces the previous two-argument `(id, payload)` API. Every handler now receives the full picture:
481
595
 
482
596
  ```typescript
483
- onAction('ui_add_to_cart', (action) => {
597
+ actionService.on('ui_add_to_cart', (action) => {
484
598
  console.log(action.type); // 'ui_add_to_cart'
485
599
  console.log(action.payload); // {productId: 42, qty: 1} — fully typed
486
600
  console.log(action.context); // 'product-list' — from [action-context] ancestor
@@ -491,9 +605,9 @@ onAction('ui_add_to_cart', (action) => {
491
605
  Modifiers can enrich `meta` before the action reaches subscribers:
492
606
 
493
607
  ```typescript
494
- import {registerModifier} from '@alwatr/flux';
608
+ import {actionService} from '@alwatr/flux';
495
609
 
496
- registerModifier('trace', (_event, _element, action) => {
610
+ actionService.registerModifier('trace', (_event, _element, action) => {
497
611
  action.meta ??= {};
498
612
  action.meta['traceId'] = crypto.randomUUID();
499
613
  return true;
@@ -531,10 +645,10 @@ bun add @alwatr/flux
531
645
  ### 1. Bootstrap the Application
532
646
 
533
647
  ```typescript
534
- import {setupActionDelegation, dispatchPageReady} from '@alwatr/flux';
648
+ import {actionService, dispatchPageReady} from '@alwatr/flux';
535
649
 
536
650
  // Activate global event delegation (call once at app start)
537
- setupActionDelegation();
651
+ actionService.setupDelegation();
538
652
 
539
653
  // Dispatch page-ready signal (for MPA routing)
540
654
  dispatchPageReady();
@@ -569,19 +683,19 @@ export const counterSignal = createStateSignal({
569
683
 
570
684
  ```typescript
571
685
  // src/controllers.ts
572
- import {onAction} from '@alwatr/flux';
686
+ import {actionService} from '@alwatr/flux';
573
687
  import {counterSignal} from './state.js';
574
688
 
575
- onAction('ui_increment', () => {
689
+ actionService.on('ui_increment', () => {
576
690
  counterSignal.update((count) => count + 1);
577
691
  });
578
692
 
579
- onAction('ui_decrement', () => {
693
+ actionService.on('ui_decrement', () => {
580
694
  counterSignal.update((count) => count - 1);
581
695
  });
582
696
 
583
697
  // Handler receives the full Action object — payload is typed from ActionRecord
584
- onAction('ui_set_count', (action) => {
698
+ actionService.on('ui_set_count', (action) => {
585
699
  counterSignal.set(action.payload); // action.payload: number
586
700
  });
587
701
  ```
@@ -616,11 +730,11 @@ onAction('ui_set_count', (action) => {
616
730
 
617
731
  ```typescript
618
732
  // main.js
619
- import {setupActionDelegation} from '@alwatr/flux';
733
+ import {actionService} from '@alwatr/flux';
620
734
  import {counterSignal} from './state.js';
621
735
  import './controllers.js'; // Register action handlers
622
736
 
623
- setupActionDelegation();
737
+ actionService.setupDelegation();
624
738
 
625
739
  // Subscribe to state changes and update DOM
626
740
  counterSignal.subscribe((count) => {
@@ -732,38 +846,66 @@ const mapped = createMappedSignal(source, {
732
846
  });
733
847
  ```
734
848
 
849
+ #### `createFsmService(config)`
850
+
851
+ Instantiates a Finite State Machine service using the given configuration:
852
+
853
+ ```typescript
854
+ import {createFsmService} from '@alwatr/flux';
855
+
856
+ const myService = createFsmService({
857
+ name: 'my-fsm',
858
+ initial: 'idle',
859
+ context: {retries: 0},
860
+ states: {
861
+ idle: {
862
+ on: {START: {target: 'working'}},
863
+ },
864
+ working: {
865
+ on: {SUCCESS: {target: 'idle'}},
866
+ },
867
+ },
868
+ });
869
+ ```
870
+
871
+ See the complete [FSM Package README](https://github.com/Alwatr/alwatr/tree/next/pkg/fsm#readme) for advanced FSM configuration details (Persistence, Guards, Actors, etc.).
872
+
735
873
  ---
736
874
 
737
875
  ### Actions
738
876
 
739
- #### `setupActionDelegation(eventTypes?)`
877
+ #### `actionService`
878
+
879
+ The pre-instantiated singleton instance of `ActionService` exported for declarative event delegation and action dispatching.
880
+
881
+ ##### `actionService.setupDelegation(eventTypes?)`
740
882
 
741
- Activates global event delegation. Call once at app bootstrap.
883
+ Activates global event delegation capture listeners on `document.body`.
742
884
 
743
885
  ```typescript
744
- import {setupActionDelegation, DEFAULT_DELEGATED_EVENTS} from '@alwatr/flux';
886
+ import {actionService, DEFAULT_DELEGATED_EVENTS} from '@alwatr/flux';
745
887
 
746
888
  // Use defaults (click, submit, input, change)
747
- setupActionDelegation();
889
+ actionService.setupDelegation();
748
890
 
749
891
  // Or add custom events
750
- setupActionDelegation([...DEFAULT_DELEGATED_EVENTS, 'keydown', 'focus']);
892
+ actionService.setupDelegation([...DEFAULT_DELEGATED_EVENTS, 'keydown', 'focus']);
751
893
  ```
752
894
 
753
- #### `onAction<K>(type, handler)`
895
+ ##### `actionService.on(type, handler)`
754
896
 
755
- Subscribes to a single typed action or an array of actions. The handler receives the full `Action<K>` object.
897
+ Subscribes to a single typed action or an array of actions.
756
898
 
757
899
  ```typescript
758
900
  // Subscribe to a single action
759
- const sub = onAction('ui_add_to_cart', (action) => {
901
+ const sub = actionService.on('ui_add_to_cart', (action) => {
760
902
  cartService.add(action.payload.productId, action.payload.qty);
761
903
  console.log(action.context); // e.g. 'product-list' or undefined
762
904
  console.log(action.meta); // any metadata set by modifiers
763
905
  });
764
906
 
765
907
  // Subscribe to multiple actions with a single handler
766
- const multiSub = onAction(['ui_increment', 'ui_decrement'], (action) => {
908
+ const multiSub = actionService.on(['ui_increment', 'ui_decrement'], (action) => {
767
909
  console.log('Action triggered:', action.type);
768
910
  });
769
911
 
@@ -771,16 +913,16 @@ sub.unsubscribe(); // Clean up when done
771
913
  multiSub.unsubscribe();
772
914
  ```
773
915
 
774
- #### `dispatchAction<K>(action)`
916
+ ##### `actionService.dispatch(action)`
775
917
 
776
- Dispatches a typed action programmatically. Takes a full `Action<K>` object.
918
+ Dispatches a typed action programmatically.
777
919
 
778
920
  ```typescript
779
- dispatchAction({type: 'navigate', payload: '/home'});
780
- dispatchAction({type: 'auth_expired', payload: undefined}); // void payload
921
+ actionService.dispatch({type: 'navigate', payload: '/home'});
922
+ actionService.dispatch({type: 'auth_expired', payload: undefined}); // void payload
781
923
 
782
924
  // With context and meta
783
- dispatchAction({
925
+ actionService.dispatch({
784
926
  type: 'upload_complete',
785
927
  payload: fileId,
786
928
  context: 'product-list',
@@ -788,17 +930,17 @@ dispatchAction({
788
930
  });
789
931
  ```
790
932
 
791
- #### `registerModifier(name, handler)`
933
+ ##### `actionService.registerModifier(name, handler)`
792
934
 
793
- Adds a custom modifier for `on-<event>` attributes. The handler receives the mutable `action` object and may write to `action.meta`.
935
+ Adds a custom modifier for `on-<event>` attributes.
794
936
 
795
937
  ```typescript
796
- registerModifier('confirm', () => {
938
+ actionService.registerModifier('confirm', () => {
797
939
  return window.confirm('Are you sure?');
798
940
  });
799
941
 
800
942
  // A modifier that stamps a trace ID into meta
801
- registerModifier('trace', (_event, _element, action) => {
943
+ actionService.registerModifier('trace', (_event, _element, action) => {
802
944
  action.meta ??= {};
803
945
  action.meta['traceId'] = crypto.randomUUID();
804
946
  return true;
@@ -809,12 +951,12 @@ registerModifier('trace', (_event, _element, action) => {
809
951
  <button on-click="ui_delete_item:42; confirm,trace">Delete</button>
810
952
  ```
811
953
 
812
- #### `registerPayloadResolver(name, resolver)`
954
+ ##### `actionService.registerPayloadResolver(name, resolver)`
813
955
 
814
956
  Adds a custom payload resolver.
815
957
 
816
958
  ```typescript
817
- registerPayloadResolver('$data-id', (_event, element) => {
959
+ actionService.registerPayloadResolver('$data-id', (_event, element) => {
818
960
  return element.dataset.id;
819
961
  });
820
962
  ```
@@ -1238,19 +1380,19 @@ export const todosSignal = createStateSignal<Todo[]>({
1238
1380
  });
1239
1381
 
1240
1382
  // controllers.ts
1241
- import {onAction} from '@alwatr/flux';
1383
+ import {actionService} from '@alwatr/flux';
1242
1384
  import {todosSignal} from './state.js';
1243
1385
 
1244
1386
  let nextId = 1;
1245
1387
 
1246
- onAction('ui_add_todo', (action) => {
1388
+ actionService.on('ui_add_todo', (action) => {
1247
1389
  todosSignal.update((todos) => [
1248
1390
  ...todos,
1249
1391
  {id: nextId++, text: action.payload, done: false},
1250
1392
  ]);
1251
1393
  });
1252
1394
 
1253
- onAction('ui_toggle_todo', (action) => {
1395
+ actionService.on('ui_toggle_todo', (action) => {
1254
1396
  todosSignal.update((todos) =>
1255
1397
  todos.map((todo) =>
1256
1398
  todo.id === action.payload ? {...todo, done: !todo.done} : todo
@@ -1258,7 +1400,7 @@ onAction('ui_toggle_todo', (action) => {
1258
1400
  );
1259
1401
  });
1260
1402
 
1261
- onAction('ui_remove_todo', (action) => {
1403
+ actionService.on('ui_remove_todo', (action) => {
1262
1404
  todosSignal.update((todos) => todos.filter((t) => t.id !== action.payload));
1263
1405
  });
1264
1406
 
@@ -1269,11 +1411,11 @@ onAction('ui_remove_todo', (action) => {
1269
1411
  </div>
1270
1412
 
1271
1413
  // main.ts
1272
- import {setupActionDelegation, html, render} from '@alwatr/flux';
1414
+ import {actionService, html, render} from '@alwatr/flux';
1273
1415
  import {todosSignal} from './state.js';
1274
1416
  import './controllers.js';
1275
1417
 
1276
- setupActionDelegation();
1418
+ actionService.setupDelegation();
1277
1419
 
1278
1420
  todosSignal.subscribe((todos) => {
1279
1421
  render(
@@ -1307,7 +1449,7 @@ todosSignal.subscribe((todos) => {
1307
1449
  - **[@alwatr/action](https://github.com/Alwatr/alwatr/tree/next/pkg/nanolib/action)** — Global event delegation action bus (part of Flux)
1308
1450
  - **[@alwatr/directive](https://github.com/Alwatr/alwatr/tree/next/pkg/nanolib/directive)** — Attribute-based DOM directives (part of Flux)
1309
1451
  - **[@alwatr/embedded-data](https://github.com/Alwatr/alwatr/tree/next/pkg/nanolib/embedded-data)** — Extract and validate embedded JSON from DOM script tags for SSR hydration (part of Flux)
1310
- - **[@alwatr/fsm](https://github.com/Alwatr/alwatr/tree/next/pkg/fsm)** — Type-safe Finite State Machine
1452
+ - **[@alwatr/fsm](https://github.com/Alwatr/alwatr/tree/next/pkg/fsm)** — Type-safe Finite State Machine (part of Flux)
1311
1453
  - **[@alwatr/nanotron](https://github.com/Alwatr/alwatr/tree/next/pkg/nanotron)** — Lightweight API server framework
1312
1454
  - **[@alwatr/nitrobase](https://github.com/Alwatr/alwatr/tree/next/pkg/nitrobase)** — In-memory JSON database
1313
1455
  - **[@alwatr/fetch](https://github.com/Alwatr/alwatr/tree/next/pkg/nanolib/fetch)** — Enhanced fetch with retry, cache, deduplication
package/dist/main.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from '@alwatr/signal';
2
2
  export * from '@alwatr/action';
3
3
  export * from '@alwatr/directive';
4
4
  export * from '@alwatr/embedded-data';
5
+ export * from '@alwatr/fsm';
5
6
  export * from '@alwatr/keyboard-shortcut';
6
7
  export * from '@alwatr/render-state';
7
8
  export * from '@alwatr/local-storage';
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAGA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,mBAAmB,qBAAqB,CAAC"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAGA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,mBAAmB,qBAAqB,CAAC"}
package/dist/main.js CHANGED
@@ -1,5 +1,5 @@
1
- /* 📦 @alwatr/flux v9.26.0 */
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};
1
+ /* 📦 @alwatr/flux v9.28.0 */
2
+ export*from"@alwatr/signal";export*from"@alwatr/action";export*from"@alwatr/directive";export*from"@alwatr/embedded-data";export*from"@alwatr/fsm";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 x}from"lit-html";import{unsafeSVG as m}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,m as unsafeSVG,p as svg,I as repeat,f as render,x as nothing,t as noChange,a as mathml,i as ifDefined,e as html,b as classMap,s as cache};
3
3
 
4
- //# debugId=B53609D2635793FE64756E2164756E21
4
+ //# debugId=F1AB5B823C55946064756E2164756E21
5
5
  //# sourceMappingURL=main.js.map
package/dist/main.js.map CHANGED
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts", "../src/lit-html.ts"],
4
4
  "sourcesContent": [
5
- "// UI and reactive bundle — signals, actions, directives, and client-side storage.\n// This package aggregates all UI-layer nanolibs for convenient single-import usage.\n\nexport * from '@alwatr/signal';\nexport * from '@alwatr/action';\nexport * from '@alwatr/directive';\nexport * from '@alwatr/embedded-data';\nexport * from '@alwatr/keyboard-shortcut';\nexport * from '@alwatr/render-state';\nexport * from '@alwatr/local-storage';\nexport * from '@alwatr/session-storage';\nexport * from '@alwatr/page-ready';\nexport * from './lit-html.js';\nexport type * from '@alwatr/type-helper';\n",
5
+ "// UI and reactive bundle — signals, actions, directives, and client-side storage.\n// This package aggregates all UI-layer nanolibs for convenient single-import usage.\n\nexport * from '@alwatr/signal';\nexport * from '@alwatr/action';\nexport * from '@alwatr/directive';\nexport * from '@alwatr/embedded-data';\nexport * from '@alwatr/fsm';\nexport * from '@alwatr/keyboard-shortcut';\nexport * from '@alwatr/render-state';\nexport * from '@alwatr/local-storage';\nexport * from '@alwatr/session-storage';\nexport * from '@alwatr/page-ready';\nexport * from './lit-html.js';\nexport type * from '@alwatr/type-helper';\n",
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
- "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": "B53609D2635793FE64756E2164756E21",
8
+ "mappings": ";AAGA,4BACA,4BACA,+BACA,mCACA,yBACA,uCACA,kCACA,mCACA,qCACA,gCCkBA,eACE,SACA,YACA,YACA,cACA,aACA,iBAMF,oBAAQ,0CACR,oBAAQ,0CACR,gBAAQ,qCACR,mBAAQ,yCACR,eAAQ,oCACR,iBAAQ",
9
+ "debugId": "F1AB5B823C55946064756E2164756E21",
10
10
  "names": []
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alwatr/flux",
3
- "version": "9.26.0",
3
+ "version": "9.28.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,13 @@
21
21
  },
22
22
  "sideEffects": false,
23
23
  "dependencies": {
24
- "@alwatr/action": "9.26.0",
24
+ "@alwatr/action": "9.28.0",
25
25
  "@alwatr/directive": "9.26.0",
26
26
  "@alwatr/embedded-data": "9.25.0",
27
- "@alwatr/keyboard-shortcut": "9.26.0",
27
+ "@alwatr/fsm": "9.28.0",
28
+ "@alwatr/keyboard-shortcut": "9.28.0",
28
29
  "@alwatr/local-storage": "9.25.0",
29
- "@alwatr/page-ready": "9.26.0",
30
+ "@alwatr/page-ready": "9.27.0",
30
31
  "@alwatr/render-state": "9.25.0",
31
32
  "@alwatr/session-storage": "9.25.0",
32
33
  "@alwatr/signal": "9.26.0",
@@ -84,5 +85,5 @@
84
85
  "ui",
85
86
  "unidirectional-data-flow"
86
87
  ],
87
- "gitHead": "ef62969b649929413c640e69d241f4e99d6062e8"
88
+ "gitHead": "d60f1d986e5ff44f871d38231f1f2be60833140b"
88
89
  }
package/src/main.ts CHANGED
@@ -5,6 +5,7 @@ export * from '@alwatr/signal';
5
5
  export * from '@alwatr/action';
6
6
  export * from '@alwatr/directive';
7
7
  export * from '@alwatr/embedded-data';
8
+ export * from '@alwatr/fsm';
8
9
  export * from '@alwatr/keyboard-shortcut';
9
10
  export * from '@alwatr/render-state';
10
11
  export * from '@alwatr/local-storage';