@alwatr/flux 9.16.0 → 9.18.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 +288 -68
- package/dist/lit-html.d.ts +36 -0
- package/dist/lit-html.d.ts.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -3
- package/dist/main.js.map +5 -4
- package/package.json +7 -6
- package/src/lit-html.ts +41 -0
- package/src/main.ts +1 -0
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ No magic. No hidden re-renders. No performance cliffs.
|
|
|
52
52
|
|
|
53
53
|
### 3. **Absolute Type Safety**
|
|
54
54
|
|
|
55
|
-
Through TypeScript's **Declaration Merging**, the entire action bus is fully typed
|
|
55
|
+
Through TypeScript's **Declaration Merging**, the entire action bus is fully typed. Every action is a single **`Action<K>`** object (Alwatr Flux Standard Action — AFSA) carrying `type`, `payload`, `context`, and `meta`:
|
|
56
56
|
|
|
57
57
|
```typescript
|
|
58
58
|
// Define your actions once
|
|
@@ -64,14 +64,16 @@ declare module '@alwatr/flux' {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
// Get compile-time safety everywhere
|
|
68
|
-
onAction('add_to_cart', (
|
|
69
|
-
//
|
|
70
|
-
cartService.add(
|
|
67
|
+
// Get compile-time safety everywhere — handler receives the full Action object
|
|
68
|
+
onAction('add_to_cart', (action) => {
|
|
69
|
+
// action.payload is typed as {productId: number; qty: number}
|
|
70
|
+
cartService.add(action.payload.productId, action.payload.qty);
|
|
71
|
+
// action.context is the nearest [action-context] ancestor value (or undefined)
|
|
72
|
+
console.log(action.context); // e.g. 'product-list'
|
|
71
73
|
});
|
|
72
74
|
|
|
73
|
-
dispatchAction('add_to_cart', {productId: 42, qty: 1}); // ✅
|
|
74
|
-
dispatchAction('add_to_cart', 'wrong'); // ❌ Compile error
|
|
75
|
+
dispatchAction({type: 'add_to_cart', payload: {productId: 42, qty: 1}}); // ✅
|
|
76
|
+
dispatchAction({type: 'add_to_cart', payload: 'wrong'}); // ❌ Compile error
|
|
75
77
|
```
|
|
76
78
|
|
|
77
79
|
---
|
|
@@ -120,7 +122,7 @@ lastName.set('Smith'); // Only fullName and the effect re-run — nothing else
|
|
|
120
122
|
|
|
121
123
|
### 🧩 **Declarative HTML Syntax**
|
|
122
124
|
|
|
123
|
-
Connect DOM events to typed actions without writing JavaScript:
|
|
125
|
+
Connect DOM events to typed actions without writing JavaScript. Wrap elements in `[action-context]` to scope the same action type to different UI regions:
|
|
124
126
|
|
|
125
127
|
```html
|
|
126
128
|
<!-- Simple action -->
|
|
@@ -153,6 +155,28 @@ Connect DOM events to typed actions without writing JavaScript:
|
|
|
153
155
|
|
|
154
156
|
<!-- Fire once and remove -->
|
|
155
157
|
<button on-click="track_impression:hero_banner; once">Learn More</button>
|
|
158
|
+
|
|
159
|
+
<!-- Context scoping — same action type, different regions -->
|
|
160
|
+
<section action-context="volume">
|
|
161
|
+
<input
|
|
162
|
+
type="range"
|
|
163
|
+
on-input="slider:change:$value"
|
|
164
|
+
/>
|
|
165
|
+
</section>
|
|
166
|
+
<section action-context="brightness">
|
|
167
|
+
<input
|
|
168
|
+
type="range"
|
|
169
|
+
on-input="slider:change:$value"
|
|
170
|
+
/>
|
|
171
|
+
</section>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// Handler receives the full Action object — payload, context, and meta together
|
|
176
|
+
onAction('slider:change', (action) => {
|
|
177
|
+
if (action.context === 'volume') audioService.setVolume(Number(action.payload));
|
|
178
|
+
if (action.context === 'brightness') displayService.setBrightness(Number(action.payload));
|
|
179
|
+
});
|
|
156
180
|
```
|
|
157
181
|
|
|
158
182
|
**Built-in modifiers:**
|
|
@@ -308,55 +332,59 @@ createEffect({
|
|
|
308
332
|
Flux implements a **strict layered architecture** where each layer has a single responsibility:
|
|
309
333
|
|
|
310
334
|
```
|
|
311
|
-
|
|
312
|
-
│ VIEW LAYER
|
|
313
|
-
│ (HTML templates, Directives, lit-html rendering)
|
|
314
|
-
│
|
|
315
|
-
│ • Reads state from Signals
|
|
316
|
-
│ • Dispatches Actions via on-<event> attributes
|
|
317
|
-
│ • Never manipulates state directly
|
|
318
|
-
|
|
335
|
+
┌───────────────────────────────────────────────────────────┐
|
|
336
|
+
│ VIEW LAYER │
|
|
337
|
+
│ (HTML templates, Directives, lit-html rendering) │
|
|
338
|
+
│ │
|
|
339
|
+
│ • Reads state from Signals │
|
|
340
|
+
│ • Dispatches Actions via on-<event> attributes │
|
|
341
|
+
│ • Never manipulates state directly │
|
|
342
|
+
└──────────────────┬────────────────────────────────────────┘
|
|
319
343
|
│ on-click="add_to_cart:42"
|
|
320
344
|
▼
|
|
321
|
-
|
|
322
|
-
│ ACTION LAYER
|
|
323
|
-
│ (@alwatr/action — Global Event Delegation)
|
|
324
|
-
│
|
|
325
|
-
│ • Captures DOM events via document.body listener
|
|
326
|
-
│ •
|
|
327
|
-
│ •
|
|
328
|
-
│ •
|
|
329
|
-
│ •
|
|
330
|
-
|
|
331
|
-
|
|
345
|
+
┌───────────────────────────────────────────────────────────┐
|
|
346
|
+
│ ACTION LAYER │
|
|
347
|
+
│ (@alwatr/action — Global Event Delegation + AFSA) │
|
|
348
|
+
│ │
|
|
349
|
+
│ • Captures DOM events via document.body listener │
|
|
350
|
+
│ • Resolves [action-context] ancestor → action.context │
|
|
351
|
+
│ • Parses on-<event> attributes │
|
|
352
|
+
│ • Runs modifiers (prevent, validate, once) │
|
|
353
|
+
│ • Modifiers may enrich action.meta │
|
|
354
|
+
│ • Resolves payload ($value, $formdata) │
|
|
355
|
+
│ • Dispatches full Action {type, payload, context, meta} │
|
|
356
|
+
└──────────────────┬────────────────────────────────────────┘
|
|
357
|
+
│ dispatchAction({type: 'add_to_cart', payload: 42, context: 'cart'})
|
|
332
358
|
▼
|
|
333
|
-
|
|
334
|
-
│ CONTROLLER LAYER
|
|
335
|
-
│ (Business Logic, Services, Use Cases)
|
|
336
|
-
│
|
|
337
|
-
│ • Subscribes to Actions via onAction()
|
|
338
|
-
│ •
|
|
339
|
-
│
|
|
340
|
-
│ •
|
|
341
|
-
|
|
359
|
+
┌───────────────────────────────────────────────────────────┐
|
|
360
|
+
│ CONTROLLER LAYER │
|
|
361
|
+
│ (Business Logic, Services, Use Cases) │
|
|
362
|
+
│ │
|
|
363
|
+
│ • Subscribes to Actions via onAction() │
|
|
364
|
+
│ • Receives full Action object (type, payload, context, │
|
|
365
|
+
│ meta) — no need to pass context separately │
|
|
366
|
+
│ • Executes business logic │
|
|
367
|
+
│ • Updates State via Signal.set() │
|
|
368
|
+
│ • Never touches DOM directly │
|
|
369
|
+
└──────────────────┬────────────────────────────────────────┘
|
|
342
370
|
│ cartSignal.set(newCart)
|
|
343
371
|
▼
|
|
344
|
-
|
|
345
|
-
│ STATE LAYER
|
|
346
|
-
│ (@alwatr/signal — Reactive State Management)
|
|
347
|
-
│
|
|
348
|
-
│ • StateSignal — mutable state
|
|
349
|
-
│ • ComputedSignal — derived state (memoized)
|
|
350
|
-
│ • EffectSignal — side effects
|
|
351
|
-
│ • PersistentStateSignal — localStorage sync
|
|
352
|
-
│ • SessionStateSignal — sessionStorage sync
|
|
353
|
-
|
|
372
|
+
┌───────────────────────────────────────────────────────────┐
|
|
373
|
+
│ STATE LAYER │
|
|
374
|
+
│ (@alwatr/signal — Reactive State Management) │
|
|
375
|
+
│ │
|
|
376
|
+
│ • StateSignal — mutable state │
|
|
377
|
+
│ • ComputedSignal — derived state (memoized) │
|
|
378
|
+
│ • EffectSignal — side effects │
|
|
379
|
+
│ • PersistentStateSignal — localStorage sync │
|
|
380
|
+
│ • SessionStateSignal — sessionStorage sync │
|
|
381
|
+
└──────────────────┬────────────────────────────────────────┘
|
|
354
382
|
│ signal.subscribe(render)
|
|
355
383
|
▼
|
|
356
|
-
|
|
357
|
-
│ VIEW LAYER
|
|
358
|
-
│ (Re-render only affected DOM nodes)
|
|
359
|
-
|
|
384
|
+
┌───────────────────────────────────────────────────────────┐
|
|
385
|
+
│ VIEW LAYER │
|
|
386
|
+
│ (Re-render only affected DOM nodes) │
|
|
387
|
+
└───────────────────────────────────────────────────────────┘
|
|
360
388
|
```
|
|
361
389
|
|
|
362
390
|
**Key architectural benefits:**
|
|
@@ -369,6 +397,63 @@ Flux implements a **strict layered architecture** where each layer has a single
|
|
|
369
397
|
|
|
370
398
|
---
|
|
371
399
|
|
|
400
|
+
## 🎯 The Action Object (AFSA)
|
|
401
|
+
|
|
402
|
+
Every action flowing through the bus — whether triggered from HTML attributes or dispatched programmatically — is a single **`Action<K>`** object (Alwatr Flux Standard Action):
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
interface Action<K extends keyof ActionRecord> {
|
|
406
|
+
/** Action identifier — must be a key of ActionRecord. */
|
|
407
|
+
type: K;
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* DOM context from the nearest [action-context] ancestor.
|
|
411
|
+
* undefined for programmatic dispatches or when no ancestor exists.
|
|
412
|
+
* Example: 'product-list', 'checkout-form', 'volume-slider'
|
|
413
|
+
*/
|
|
414
|
+
context?: string;
|
|
415
|
+
|
|
416
|
+
/** Business payload — type is inferred from ActionRecord[K]. */
|
|
417
|
+
payload: ActionRecord[K];
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Open-ended metadata bag for cross-cutting concerns.
|
|
421
|
+
* Modifiers in the delegation pipeline may write to this before
|
|
422
|
+
* the action reaches subscribers.
|
|
423
|
+
*/
|
|
424
|
+
meta?: Record<string, unknown>;
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
This unified structure replaces the previous two-argument `(id, payload)` API. Every handler now receives the full picture:
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
onAction('add_to_cart', (action) => {
|
|
432
|
+
console.log(action.type); // 'add_to_cart'
|
|
433
|
+
console.log(action.payload); // {productId: 42, qty: 1} — fully typed
|
|
434
|
+
console.log(action.context); // 'product-list' — from [action-context] ancestor
|
|
435
|
+
console.log(action.meta); // {traceId: '…'} — set by modifiers, or undefined
|
|
436
|
+
});
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Modifiers can enrich `meta` before the action reaches subscribers:
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
import {registerModifier} from '@alwatr/flux';
|
|
443
|
+
|
|
444
|
+
registerModifier('trace', (_event, _element, action) => {
|
|
445
|
+
action.meta ??= {};
|
|
446
|
+
action.meta['traceId'] = crypto.randomUUID();
|
|
447
|
+
return true;
|
|
448
|
+
});
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
```html
|
|
452
|
+
<button on-click="submit_order:42; trace">Place Order</button>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
372
457
|
## 📦 Installation
|
|
373
458
|
|
|
374
459
|
```bash
|
|
@@ -443,8 +528,9 @@ onAction('decrement', () => {
|
|
|
443
528
|
counterSignal.update((count) => count - 1);
|
|
444
529
|
});
|
|
445
530
|
|
|
446
|
-
|
|
447
|
-
|
|
531
|
+
// Handler receives the full Action object — payload is typed from ActionRecord
|
|
532
|
+
onAction('set_count', (action) => {
|
|
533
|
+
counterSignal.set(action.payload); // action.payload: number
|
|
448
534
|
});
|
|
449
535
|
```
|
|
450
536
|
|
|
@@ -612,39 +698,56 @@ setupActionDelegation();
|
|
|
612
698
|
setupActionDelegation([...DEFAULT_DELEGATED_EVENTS, 'keydown', 'focus']);
|
|
613
699
|
```
|
|
614
700
|
|
|
615
|
-
#### `onAction<K>(
|
|
701
|
+
#### `onAction<K>(type, handler)`
|
|
616
702
|
|
|
617
|
-
Subscribes to a typed action.
|
|
703
|
+
Subscribes to a typed action. The handler receives the full `Action<K>` object.
|
|
618
704
|
|
|
619
705
|
```typescript
|
|
620
|
-
const sub = onAction('add_to_cart', (
|
|
621
|
-
cartService.add(
|
|
706
|
+
const sub = onAction('add_to_cart', (action) => {
|
|
707
|
+
cartService.add(action.payload.productId, action.payload.qty);
|
|
708
|
+
console.log(action.context); // e.g. 'product-list' or undefined
|
|
709
|
+
console.log(action.meta); // any metadata set by modifiers
|
|
622
710
|
});
|
|
623
711
|
|
|
624
712
|
sub.unsubscribe(); // Clean up when done
|
|
625
713
|
```
|
|
626
714
|
|
|
627
|
-
#### `dispatchAction<K>(
|
|
715
|
+
#### `dispatchAction<K>(action)`
|
|
628
716
|
|
|
629
|
-
Dispatches a typed action programmatically.
|
|
717
|
+
Dispatches a typed action programmatically. Takes a full `Action<K>` object.
|
|
630
718
|
|
|
631
719
|
```typescript
|
|
632
|
-
dispatchAction('navigate', '/home');
|
|
633
|
-
dispatchAction('logout'); // void payload
|
|
720
|
+
dispatchAction({type: 'navigate', payload: '/home'});
|
|
721
|
+
dispatchAction({type: 'logout', payload: undefined}); // void payload
|
|
722
|
+
|
|
723
|
+
// With context and meta
|
|
724
|
+
dispatchAction({
|
|
725
|
+
type: 'add_to_cart',
|
|
726
|
+
payload: {productId: 42, qty: 1},
|
|
727
|
+
context: 'product-list',
|
|
728
|
+
meta: {source: 'recommendation'},
|
|
729
|
+
});
|
|
634
730
|
```
|
|
635
731
|
|
|
636
732
|
#### `registerModifier(name, handler)`
|
|
637
733
|
|
|
638
|
-
Adds a custom modifier for `on-<event>` attributes.
|
|
734
|
+
Adds a custom modifier for `on-<event>` attributes. The handler receives the mutable `action` object and may write to `action.meta`.
|
|
639
735
|
|
|
640
736
|
```typescript
|
|
641
737
|
registerModifier('confirm', () => {
|
|
642
738
|
return window.confirm('Are you sure?');
|
|
643
739
|
});
|
|
740
|
+
|
|
741
|
+
// A modifier that stamps a trace ID into meta
|
|
742
|
+
registerModifier('trace', (_event, _element, action) => {
|
|
743
|
+
action.meta ??= {};
|
|
744
|
+
action.meta['traceId'] = crypto.randomUUID();
|
|
745
|
+
return true;
|
|
746
|
+
});
|
|
644
747
|
```
|
|
645
748
|
|
|
646
749
|
```html
|
|
647
|
-
<button on-click="delete_item:42; confirm">Delete</button>
|
|
750
|
+
<button on-click="delete_item:42; confirm,trace">Delete</button>
|
|
648
751
|
```
|
|
649
752
|
|
|
650
753
|
#### `registerPayloadResolver(name, resolver)`
|
|
@@ -842,6 +945,123 @@ renderState(currentState, {
|
|
|
842
945
|
|
|
843
946
|
---
|
|
844
947
|
|
|
948
|
+
### Template (lit-html)
|
|
949
|
+
|
|
950
|
+
`@alwatr/flux` re-exports a curated subset of [`lit-html`](https://lit.dev/docs/libraries/standalone-templates/) so you can render efficient DOM templates without adding a separate dependency.
|
|
951
|
+
|
|
952
|
+
#### `html`
|
|
953
|
+
|
|
954
|
+
Tagged template literal that produces a `TemplateResult`. lit-html parses the template once and only updates the dynamic parts on subsequent renders.
|
|
955
|
+
|
|
956
|
+
```typescript
|
|
957
|
+
import {html} from '@alwatr/flux';
|
|
958
|
+
|
|
959
|
+
const greeting = (name: string) => html`
|
|
960
|
+
<p>Hello, ${name}!</p>
|
|
961
|
+
`;
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
#### `render(value, container)`
|
|
965
|
+
|
|
966
|
+
Renders a `TemplateResult` (or any renderable value) into a DOM container. Subsequent calls efficiently patch only the changed parts.
|
|
967
|
+
|
|
968
|
+
```typescript
|
|
969
|
+
import {html, render} from '@alwatr/flux';
|
|
970
|
+
|
|
971
|
+
render(
|
|
972
|
+
html`
|
|
973
|
+
<h1>Hello World</h1>
|
|
974
|
+
`,
|
|
975
|
+
document.getElementById('app')!,
|
|
976
|
+
);
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
#### `noChange` / `nothing`
|
|
980
|
+
|
|
981
|
+
Sentinels for fine-grained control over part updates:
|
|
982
|
+
|
|
983
|
+
- **`noChange`** — leaves the current DOM value untouched (skips the update entirely)
|
|
984
|
+
- **`nothing`** — removes the node or attribute from the DOM
|
|
985
|
+
|
|
986
|
+
```typescript
|
|
987
|
+
import {html, noChange, nothing} from '@alwatr/flux';
|
|
988
|
+
|
|
989
|
+
const badge = (count: number | undefined) => html`
|
|
990
|
+
<span class="badge">
|
|
991
|
+
${count === undefined ? nothing
|
|
992
|
+
: count === 0 ? noChange
|
|
993
|
+
: count}
|
|
994
|
+
</span>
|
|
995
|
+
`;
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
#### `ifDefined(value)`
|
|
999
|
+
|
|
1000
|
+
Renders the attribute only when `value` is not `undefined`; removes the attribute otherwise.
|
|
1001
|
+
|
|
1002
|
+
```typescript
|
|
1003
|
+
import {html, ifDefined} from '@alwatr/flux';
|
|
1004
|
+
|
|
1005
|
+
const link = (href?: string) => html`
|
|
1006
|
+
<a href=${ifDefined(href)}>Click</a>
|
|
1007
|
+
`;
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
#### `cache(value)`
|
|
1011
|
+
|
|
1012
|
+
Caches rendered templates keyed by their `TemplateResult` identity. Avoids re-parsing the template string when switching between a fixed set of templates (e.g. tab panels).
|
|
1013
|
+
|
|
1014
|
+
```typescript
|
|
1015
|
+
import {html, cache} from '@alwatr/flux';
|
|
1016
|
+
|
|
1017
|
+
const panel = (tab: 'home' | 'settings') =>
|
|
1018
|
+
cache(
|
|
1019
|
+
tab === 'home' ?
|
|
1020
|
+
html`
|
|
1021
|
+
<home-panel></home-panel>
|
|
1022
|
+
`
|
|
1023
|
+
: html`
|
|
1024
|
+
<settings-panel></settings-panel>
|
|
1025
|
+
`,
|
|
1026
|
+
);
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
#### `classMap(classInfo)`
|
|
1030
|
+
|
|
1031
|
+
Efficiently toggles CSS classes from a `{[className]: boolean}` object. Only the classes present in the map are touched; others are left unchanged.
|
|
1032
|
+
|
|
1033
|
+
```typescript
|
|
1034
|
+
import {html, classMap} from '@alwatr/flux';
|
|
1035
|
+
|
|
1036
|
+
const button = (isActive: boolean, isDisabled: boolean) => html`
|
|
1037
|
+
<button class=${classMap({active: isActive, disabled: isDisabled})}>Click</button>
|
|
1038
|
+
`;
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
#### `when(condition, trueCase, falseCase?)`
|
|
1042
|
+
|
|
1043
|
+
Conditional rendering helper. Cleaner than ternary expressions for template branches.
|
|
1044
|
+
|
|
1045
|
+
```typescript
|
|
1046
|
+
import {html, when} from '@alwatr/flux';
|
|
1047
|
+
|
|
1048
|
+
const status = (isLoading: boolean) => html`
|
|
1049
|
+
<div>
|
|
1050
|
+
${when(
|
|
1051
|
+
isLoading,
|
|
1052
|
+
() => html`
|
|
1053
|
+
<spinner-element></spinner-element>
|
|
1054
|
+
`,
|
|
1055
|
+
() => html`
|
|
1056
|
+
<content-element></content-element>
|
|
1057
|
+
`,
|
|
1058
|
+
)}
|
|
1059
|
+
</div>
|
|
1060
|
+
`;
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
845
1065
|
## 🆚 Why Choose Alwatr Flux?
|
|
846
1066
|
|
|
847
1067
|
| Feature | React + Redux | Solid.js | Svelte | **Alwatr Flux** 🌊 |
|
|
@@ -889,23 +1109,23 @@ import {todosSignal} from './state.js';
|
|
|
889
1109
|
|
|
890
1110
|
let nextId = 1;
|
|
891
1111
|
|
|
892
|
-
onAction('add_todo', (
|
|
1112
|
+
onAction('add_todo', (action) => {
|
|
893
1113
|
todosSignal.update((todos) => [
|
|
894
1114
|
...todos,
|
|
895
|
-
{id: nextId++, text, done: false},
|
|
1115
|
+
{id: nextId++, text: action.payload, done: false},
|
|
896
1116
|
]);
|
|
897
1117
|
});
|
|
898
1118
|
|
|
899
|
-
onAction('toggle_todo', (
|
|
1119
|
+
onAction('toggle_todo', (action) => {
|
|
900
1120
|
todosSignal.update((todos) =>
|
|
901
1121
|
todos.map((todo) =>
|
|
902
|
-
todo.id ===
|
|
1122
|
+
todo.id === action.payload ? {...todo, done: !todo.done} : todo
|
|
903
1123
|
)
|
|
904
1124
|
);
|
|
905
1125
|
});
|
|
906
1126
|
|
|
907
|
-
onAction('remove_todo', (
|
|
908
|
-
todosSignal.update((todos) => todos.filter((t) => t.id !==
|
|
1127
|
+
onAction('remove_todo', (action) => {
|
|
1128
|
+
todosSignal.update((todos) => todos.filter((t) => t.id !== action.payload));
|
|
909
1129
|
});
|
|
910
1130
|
|
|
911
1131
|
// view.html
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated re-exports from `lit-html` for use within `@alwatr/flux`.
|
|
3
|
+
*
|
|
4
|
+
* Only the subset of `lit-html` APIs that are commonly needed in a Flux-based
|
|
5
|
+
* application is exported here. This keeps the public surface minimal and
|
|
6
|
+
* avoids pulling in advanced directive utilities that most consumers never use.
|
|
7
|
+
*
|
|
8
|
+
* **Exported APIs:**
|
|
9
|
+
* - `html` — tagged template literal that produces a `TemplateResult`
|
|
10
|
+
* - `render` — renders a `TemplateResult` into a DOM container
|
|
11
|
+
* - `noChange` — sentinel that tells lit-html to leave the current part value unchanged
|
|
12
|
+
* - `nothing` — sentinel that renders nothing (removes the node/attribute)
|
|
13
|
+
* - `ifDefined` — renders a value only when it is not `undefined`
|
|
14
|
+
* - `cache` — caches rendered templates to avoid re-parsing on state changes
|
|
15
|
+
* - `classMap` — efficiently sets/removes CSS classes from an object map
|
|
16
|
+
* - `when` — conditional rendering helper (`when(condition, trueCase, falseCase)`)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import {html, render, classMap, when} from '@alwatr/flux';
|
|
21
|
+
*
|
|
22
|
+
* const template = (isActive: boolean) => html`
|
|
23
|
+
* <div class=${classMap({active: isActive, hidden: !isActive})}>
|
|
24
|
+
* ${when(isActive, () => html`<span>Active</span>`, () => html`<span>Inactive</span>`)}
|
|
25
|
+
* </div>
|
|
26
|
+
* `;
|
|
27
|
+
*
|
|
28
|
+
* render(template(true), document.getElementById('app')!);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export { html, render, noChange, nothing } from 'lit-html';
|
|
32
|
+
export { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
33
|
+
export { cache } from 'lit-html/directives/cache.js';
|
|
34
|
+
export { classMap } from 'lit-html/directives/class-map.js';
|
|
35
|
+
export { when } from 'lit-html/directives/when.js';
|
|
36
|
+
//# sourceMappingURL=lit-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lit-html.d.ts","sourceRoot":"","sources":["../src/lit-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAC,MAAM,UAAU,CAAC;AAIzD,OAAO,EAAC,SAAS,EAAC,MAAM,mCAAmC,CAAC;AAC5D,OAAO,EAAC,KAAK,EAAC,MAAM,8BAA8B,CAAC;AACnD,OAAO,EAAC,QAAQ,EAAC,MAAM,kCAAkC,CAAC;AAC1D,OAAO,EAAC,IAAI,EAAC,MAAM,6BAA6B,CAAC"}
|
package/dist/main.d.ts
CHANGED
|
@@ -5,5 +5,6 @@ export * from '@alwatr/render-state';
|
|
|
5
5
|
export * from '@alwatr/local-storage';
|
|
6
6
|
export * from '@alwatr/session-storage';
|
|
7
7
|
export * from '@alwatr/page-ready';
|
|
8
|
+
export * from './lit-html.js';
|
|
8
9
|
export type * from '@alwatr/type-helper';
|
|
9
10
|
//# sourceMappingURL=main.d.ts.map
|
package/dist/main.d.ts.map
CHANGED
|
@@ -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,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,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,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.
|
|
2
|
-
export*from"@alwatr/signal";export*from"@alwatr/action";export*from"@alwatr/directive";export*from"@alwatr/render-state";export*from"@alwatr/local-storage";export*from"@alwatr/session-storage";export*from"@alwatr/page-ready";
|
|
1
|
+
/* 📦 @alwatr/flux v9.18.0 */
|
|
2
|
+
export*from"@alwatr/signal";export*from"@alwatr/action";export*from"@alwatr/directive";export*from"@alwatr/render-state";export*from"@alwatr/local-storage";export*from"@alwatr/session-storage";export*from"@alwatr/page-ready";import{html as o,render as a,noChange as t,nothing as p}from"lit-html";import{ifDefined as f}from"lit-html/directives/if-defined.js";import{cache as g}from"lit-html/directives/cache.js";import{classMap as i}from"lit-html/directives/class-map.js";import{when as s}from"lit-html/directives/when.js";export{s as when,a as render,p as nothing,t as noChange,f as ifDefined,o as html,i as classMap,g as cache};
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=432FAE968752561764756E2164756E21
|
|
5
5
|
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/main.ts"],
|
|
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/render-state';\nexport * from '@alwatr/local-storage';\nexport * from '@alwatr/session-storage';\nexport * from '@alwatr/page-ready';\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/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
|
+
"/**\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 {html, render, noChange, nothing} from 'lit-html';\n// export {Directive, PartType, directive} from 'lit-html/directive.js';\n// export {AsyncDirective} from 'lit-html/async-directive.js';\n// export {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} from 'lit-html/directives/class-map.js';\nexport {when} from 'lit-html/directives/when.js';\n\n// export type {Part, PartInfo} from 'lit-html/directive.js';\n// export type {LitUnstable} from 'lit-html';\n"
|
|
6
7
|
],
|
|
7
|
-
"mappings": ";AAGA,4BACA,4BACA,+BACA,kCACA,mCACA,qCACA",
|
|
8
|
-
"debugId": "
|
|
8
|
+
"mappings": ";AAGA,4BACA,4BACA,+BACA,kCACA,mCACA,qCACA,gCCqBA,eAAQ,YAAM,cAAQ,aAAU,iBAIhC,oBAAQ,0CACR,gBAAQ,qCACR,mBAAQ,yCACR,eAAQ",
|
|
9
|
+
"debugId": "432FAE968752561764756E2164756E21",
|
|
9
10
|
"names": []
|
|
10
11
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alwatr/flux",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.18.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,14 +21,15 @@
|
|
|
21
21
|
},
|
|
22
22
|
"sideEffects": false,
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@alwatr/action": "9.
|
|
25
|
-
"@alwatr/directive": "9.
|
|
24
|
+
"@alwatr/action": "9.17.0",
|
|
25
|
+
"@alwatr/directive": "9.18.0",
|
|
26
26
|
"@alwatr/local-storage": "9.16.0",
|
|
27
27
|
"@alwatr/page-ready": "9.16.0",
|
|
28
28
|
"@alwatr/render-state": "9.16.0",
|
|
29
29
|
"@alwatr/session-storage": "9.16.0",
|
|
30
30
|
"@alwatr/signal": "9.16.0",
|
|
31
|
-
"@alwatr/type-helper": "9.14.0"
|
|
31
|
+
"@alwatr/type-helper": "9.14.0",
|
|
32
|
+
"lit-html": "^3.3.2"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@alwatr/nano-build": "9.14.0",
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
"scripts": {
|
|
39
40
|
"b": "bun run build",
|
|
40
41
|
"build": "bun run build:ts && bun run build:es",
|
|
41
|
-
"build:es": "nano-build --preset=module src
|
|
42
|
+
"build:es": "nano-build --preset=module src/main.ts",
|
|
42
43
|
"build:ts": "tsc --build",
|
|
43
44
|
"cl": "bun run clean",
|
|
44
45
|
"clean": "rm -rfv dist *.tsbuildinfo",
|
|
@@ -81,5 +82,5 @@
|
|
|
81
82
|
"ui",
|
|
82
83
|
"unidirectional-data-flow"
|
|
83
84
|
],
|
|
84
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "ae7aed95106fd2e6d3c14f0628fc12ae8a29ea15"
|
|
85
86
|
}
|
package/src/lit-html.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated re-exports from `lit-html` for use within `@alwatr/flux`.
|
|
3
|
+
*
|
|
4
|
+
* Only the subset of `lit-html` APIs that are commonly needed in a Flux-based
|
|
5
|
+
* application is exported here. This keeps the public surface minimal and
|
|
6
|
+
* avoids pulling in advanced directive utilities that most consumers never use.
|
|
7
|
+
*
|
|
8
|
+
* **Exported APIs:**
|
|
9
|
+
* - `html` — tagged template literal that produces a `TemplateResult`
|
|
10
|
+
* - `render` — renders a `TemplateResult` into a DOM container
|
|
11
|
+
* - `noChange` — sentinel that tells lit-html to leave the current part value unchanged
|
|
12
|
+
* - `nothing` — sentinel that renders nothing (removes the node/attribute)
|
|
13
|
+
* - `ifDefined` — renders a value only when it is not `undefined`
|
|
14
|
+
* - `cache` — caches rendered templates to avoid re-parsing on state changes
|
|
15
|
+
* - `classMap` — efficiently sets/removes CSS classes from an object map
|
|
16
|
+
* - `when` — conditional rendering helper (`when(condition, trueCase, falseCase)`)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import {html, render, classMap, when} from '@alwatr/flux';
|
|
21
|
+
*
|
|
22
|
+
* const template = (isActive: boolean) => html`
|
|
23
|
+
* <div class=${classMap({active: isActive, hidden: !isActive})}>
|
|
24
|
+
* ${when(isActive, () => html`<span>Active</span>`, () => html`<span>Inactive</span>`)}
|
|
25
|
+
* </div>
|
|
26
|
+
* `;
|
|
27
|
+
*
|
|
28
|
+
* render(template(true), document.getElementById('app')!);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export {html, render, noChange, nothing} from 'lit-html';
|
|
32
|
+
// export {Directive, PartType, directive} from 'lit-html/directive.js';
|
|
33
|
+
// export {AsyncDirective} from 'lit-html/async-directive.js';
|
|
34
|
+
// export {unsafeSVG} from 'lit-html/directives/unsafe-svg.js';
|
|
35
|
+
export {ifDefined} from 'lit-html/directives/if-defined.js';
|
|
36
|
+
export {cache} from 'lit-html/directives/cache.js';
|
|
37
|
+
export {classMap} from 'lit-html/directives/class-map.js';
|
|
38
|
+
export {when} from 'lit-html/directives/when.js';
|
|
39
|
+
|
|
40
|
+
// export type {Part, PartInfo} from 'lit-html/directive.js';
|
|
41
|
+
// export type {LitUnstable} from 'lit-html';
|