@xaendar/core 0.6.4 → 0.6.6
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/dist/xaendar-core.es.d.ts +96 -0
- package/dist/xaendar-core.es.js +222 -1
- package/package.json +3 -3
|
@@ -3,6 +3,7 @@ import { Beautify } from '@xaendar/types';
|
|
|
3
3
|
import { ClassDecorator as ClassDecorator_2 } from '@xaendar/types';
|
|
4
4
|
import { Constructor } from '@xaendar/types';
|
|
5
5
|
import { EffectOptions } from '@xaendar/signals';
|
|
6
|
+
import { NoArgsFunction } from '@xaendar/types';
|
|
6
7
|
import { NoArgsVoidFunction } from '@xaendar/types';
|
|
7
8
|
import { NoArgsVoidFunction as NoArgsVoidFunction_2 } from '@xaendar/types';
|
|
8
9
|
import { RequireOne } from '@xaendar/types';
|
|
@@ -63,6 +64,19 @@ export declare type BaseWebComponentConstructor = Constructor<BaseWebComponent,
|
|
|
63
64
|
observedAttributes: string[];
|
|
64
65
|
}>;
|
|
65
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Represents a single branch of a conditional structure (`if` / `else if` / `else`).
|
|
69
|
+
*
|
|
70
|
+
* @property condition - Function that evaluates the branch condition and returns a boolean.
|
|
71
|
+
* If absent, the branch is always considered valid (represents the `else` branch).
|
|
72
|
+
* @property block - Function that, when executed, applies the branch's side effects and
|
|
73
|
+
* returns the list of cleanup (unwatch) functions generated within it.
|
|
74
|
+
*/
|
|
75
|
+
declare type Block = {
|
|
76
|
+
condition?: NoArgsFunction<boolean>;
|
|
77
|
+
block: NoArgsFunction<NoArgsVoidFunction[]>;
|
|
78
|
+
};
|
|
79
|
+
|
|
66
80
|
/**
|
|
67
81
|
* A read-only reactive value derived from other signals.
|
|
68
82
|
*
|
|
@@ -138,6 +152,37 @@ export { Event_2 as Event }
|
|
|
138
152
|
*/
|
|
139
153
|
export declare type EventOptions = Beautify<RequireOne<Omit<CustomEventInit, 'detail'>>>;
|
|
140
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Reactively iterates over a list of items, re-running the loop whenever the tracked condition changes.
|
|
157
|
+
* Previous iteration side-effects are cleaned up before each re-evaluation.
|
|
158
|
+
*
|
|
159
|
+
* @param unwatchFns - Array collecting cleanup functions for the parent scope.
|
|
160
|
+
* @param condition - A reactive function that returns the array of items to iterate over.
|
|
161
|
+
* @param forFn - A callback invoked for each item, receiving the item and its index. Must return an array of cleanup functions.
|
|
162
|
+
*/
|
|
163
|
+
export declare function _for(unwatchFns: NoArgsVoidFunction[], condition: () => unknown[], forFn: (item: unknown, index: number) => NoArgsVoidFunction[]): void;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Creates a reactive conditional structure from a list of branches.
|
|
167
|
+
*
|
|
168
|
+
* Depending on the number of branches provided, the appropriate evaluation strategy
|
|
169
|
+
* is selected:
|
|
170
|
+
* - 1 branch → simple `if` (see {@link handleIf});
|
|
171
|
+
* - 2 branches → `if` / `else` (see {@link handleIfElse});
|
|
172
|
+
* - 3+ branches → `if` / `else if` / ... / `else` (see {@link handleIfElseIf}).
|
|
173
|
+
*
|
|
174
|
+
* The evaluation is wrapped in an {@link effect}, so it is automatically re-executed
|
|
175
|
+
* whenever any signal read by the conditions changes. On each re-execution, the current
|
|
176
|
+
* state (which branch is active) and the related cleanup functions are only updated if
|
|
177
|
+
* the active branch has actually changed.
|
|
178
|
+
*
|
|
179
|
+
* @param unwatchFns - Shared array that collects all active cleanup functions.
|
|
180
|
+
* Mutated in place: the created effect and branch functions are added to and
|
|
181
|
+
* removed from this array.
|
|
182
|
+
* @param blocks - Ordered list of conditional branches to evaluate.
|
|
183
|
+
*/
|
|
184
|
+
export declare function _if(unwatchFns: NoArgsVoidFunction[], blocks: Block[]): void;
|
|
185
|
+
|
|
141
186
|
/**
|
|
142
187
|
* An `InputSignal` is a specialized `Signal.State` designed for use as a property signal in web components.
|
|
143
188
|
* It extends the base `State` signal with additional functionality to handle incoming values, such as those from HTML attributes or external sources,
|
|
@@ -192,6 +237,18 @@ export declare type InputSignalOptions<ActualValue = unknown, IncomingValue = Ac
|
|
|
192
237
|
transform?: (value: IncomingValue) => ActualValue;
|
|
193
238
|
};
|
|
194
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Builds a record of iteration context variables for a given index in the loop.
|
|
242
|
+
* Provides the current item, index, and convenience flags (`$first`, `$last`, `$even`, `$odd`).
|
|
243
|
+
*
|
|
244
|
+
* @param items - The full array being iterated.
|
|
245
|
+
* @param index - The current iteration index.
|
|
246
|
+
* @param itemAlias - The template alias name for the current item.
|
|
247
|
+
* @param indexAlias - The template alias name for the current index.
|
|
248
|
+
* @returns A record mapping alias names and built-in variables to their values.
|
|
249
|
+
*/
|
|
250
|
+
export declare function _iterationVariables(items: unknown[], index: number, itemAlias: string, indexAlias: string): Record<string, unknown>;
|
|
251
|
+
|
|
195
252
|
/**
|
|
196
253
|
* Rapresent the output type returned by an @Event Decorator in a Web Component.
|
|
197
254
|
*
|
|
@@ -293,6 +350,45 @@ declare type Signal_2<Value = any> = Signal.State<Value> & {
|
|
|
293
350
|
};
|
|
294
351
|
export { Signal_2 as Signal }
|
|
295
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Creates a reactive switch/case structure by converting it into an if/else-if chain
|
|
355
|
+
* and delegating to {@link _if}.
|
|
356
|
+
*
|
|
357
|
+
* Each case block's condition values are compared against the result of the
|
|
358
|
+
* `expression` function using strict equality (`===`). A block with
|
|
359
|
+
* `condition: null` acts as the `default` branch (mapped to the `else` branch
|
|
360
|
+
* in the underlying if/else-if chain). Multiple values per case are supported
|
|
361
|
+
* (e.g. fall-through cases) and matched with `Array.some`.
|
|
362
|
+
*
|
|
363
|
+
* Because it delegates to `_if`, the switch benefits from the same optimisation:
|
|
364
|
+
* the active branch is only re-rendered when it actually changes.
|
|
365
|
+
*
|
|
366
|
+
* @param unwatchFns - Shared array that collects all active cleanup functions.
|
|
367
|
+
* Mutated in place by the underlying {@link _if} call.
|
|
368
|
+
* @param expression - Function that evaluates the switch expression. Called
|
|
369
|
+
* reactively inside an effect so that signal reads are tracked.
|
|
370
|
+
* @param blocks - Ordered list of case branches. Each entry contains:
|
|
371
|
+
* - `condition`: array of values to match against the expression result,
|
|
372
|
+
* or `null` for the default branch.
|
|
373
|
+
* - `block`: function that applies the branch's side effects and returns
|
|
374
|
+
* its cleanup functions.
|
|
375
|
+
*/
|
|
376
|
+
export declare function _switch(unwatchFns: NoArgsVoidFunction[], expression: NoArgsFunction<unknown>, blocks: Array<{
|
|
377
|
+
condition: unknown[] | null;
|
|
378
|
+
block: NoArgsFunction<NoArgsVoidFunction[]>;
|
|
379
|
+
}>): void;
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Executes and removes the cleanup functions of the previously active branch.
|
|
383
|
+
*
|
|
384
|
+
* For each local function: removes it from the shared `unwatchFns` array (if present)
|
|
385
|
+
* and then invokes it to release resources / tear down associated subscriptions.
|
|
386
|
+
*
|
|
387
|
+
* @param unwatchFns - Shared array of active cleanup functions, mutated in place.
|
|
388
|
+
* @param localUnwatchFns - Cleanup functions of the branch to deactivate.
|
|
389
|
+
*/
|
|
390
|
+
export declare function unwatch(unwatchFns: NoArgsVoidFunction[], localUnwatchFns: NoArgsVoidFunction[]): void;
|
|
391
|
+
|
|
296
392
|
/**
|
|
297
393
|
* Decorator to define a web component
|
|
298
394
|
* @param selector Name or names of the custom element
|
package/dist/xaendar-core.es.js
CHANGED
|
@@ -401,4 +401,225 @@ function signal(value, options) {
|
|
|
401
401
|
return getter;
|
|
402
402
|
}
|
|
403
403
|
//#endregion
|
|
404
|
-
|
|
404
|
+
//#region ../packages/core/src/utils/if.utils.ts
|
|
405
|
+
/**
|
|
406
|
+
* Creates a reactive conditional structure from a list of branches.
|
|
407
|
+
*
|
|
408
|
+
* Depending on the number of branches provided, the appropriate evaluation strategy
|
|
409
|
+
* is selected:
|
|
410
|
+
* - 1 branch → simple `if` (see {@link handleIf});
|
|
411
|
+
* - 2 branches → `if` / `else` (see {@link handleIfElse});
|
|
412
|
+
* - 3+ branches → `if` / `else if` / ... / `else` (see {@link handleIfElseIf}).
|
|
413
|
+
*
|
|
414
|
+
* The evaluation is wrapped in an {@link effect}, so it is automatically re-executed
|
|
415
|
+
* whenever any signal read by the conditions changes. On each re-execution, the current
|
|
416
|
+
* state (which branch is active) and the related cleanup functions are only updated if
|
|
417
|
+
* the active branch has actually changed.
|
|
418
|
+
*
|
|
419
|
+
* @param unwatchFns - Shared array that collects all active cleanup functions.
|
|
420
|
+
* Mutated in place: the created effect and branch functions are added to and
|
|
421
|
+
* removed from this array.
|
|
422
|
+
* @param blocks - Ordered list of conditional branches to evaluate.
|
|
423
|
+
*/
|
|
424
|
+
function _if(unwatchFns, blocks) {
|
|
425
|
+
let state = null;
|
|
426
|
+
let localUnwatchFns = new Array();
|
|
427
|
+
let fn;
|
|
428
|
+
switch (blocks.length) {
|
|
429
|
+
case 1:
|
|
430
|
+
fn = () => handleIf(blocks[0], state, unwatchFns, localUnwatchFns);
|
|
431
|
+
break;
|
|
432
|
+
case 2:
|
|
433
|
+
fn = () => handleIfElse(blocks[0], blocks[1], state, unwatchFns, localUnwatchFns);
|
|
434
|
+
break;
|
|
435
|
+
default: fn = () => handleIfElseIf(blocks, state, unwatchFns, localUnwatchFns);
|
|
436
|
+
}
|
|
437
|
+
const unlistener = effect(() => {
|
|
438
|
+
const retVal = fn();
|
|
439
|
+
if (retVal) {
|
|
440
|
+
state = retVal.state;
|
|
441
|
+
localUnwatchFns = retVal.fns;
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
unwatchFns.push(unlistener);
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Handles the simple `if` case (a single branch, no `else`).
|
|
448
|
+
*
|
|
449
|
+
* If the condition is true, the branch is activated (state `0`); otherwise, any
|
|
450
|
+
* previously active branch is deactivated by resetting the state to `null` and
|
|
451
|
+
* executing an empty block.
|
|
452
|
+
*
|
|
453
|
+
* @param ifBlock - The `if` branch to evaluate.
|
|
454
|
+
* @param state - The current state (index of the active branch, or `null` if none).
|
|
455
|
+
* @param unwatchFns - Shared array of active cleanup functions.
|
|
456
|
+
* @param localUnwatchFns - Cleanup functions generated by the last branch activation.
|
|
457
|
+
* @returns The new state and new cleanup functions if the active branch changed,
|
|
458
|
+
* otherwise `undefined`.
|
|
459
|
+
*/
|
|
460
|
+
function handleIf(ifBlock, state, unwatchFns, localUnwatchFns) {
|
|
461
|
+
return ifBlock.condition() ? checkAndUpdateState(state, 0, ifBlock.block, unwatchFns, localUnwatchFns) : checkAndUpdateState(state, null, () => [], unwatchFns, localUnwatchFns);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Handles the `if` / `else` case (exactly two branches).
|
|
465
|
+
*
|
|
466
|
+
* If the `if` condition is true, the first branch is activated (state `0`); otherwise,
|
|
467
|
+
* the `else` branch is activated (state `1`).
|
|
468
|
+
*
|
|
469
|
+
* @param ifBlock - The `if` branch to evaluate.
|
|
470
|
+
* @param elseBlock - The `else` branch used when the `if` condition is false.
|
|
471
|
+
* @param state - The current state (index of the active branch, or `null` if none).
|
|
472
|
+
* @param unwatchFns - Shared array of active cleanup functions.
|
|
473
|
+
* @param localUnwatchFns - Cleanup functions generated by the last branch activation.
|
|
474
|
+
* @returns The new state and new cleanup functions if the active branch changed,
|
|
475
|
+
* otherwise `undefined`.
|
|
476
|
+
*/
|
|
477
|
+
function handleIfElse(ifBlock, elseBlock, state, unwatchFns, localUnwatchFns) {
|
|
478
|
+
return ifBlock.condition() ? checkAndUpdateState(state, 0, ifBlock.block, unwatchFns, localUnwatchFns) : checkAndUpdateState(state, 1, elseBlock.block, unwatchFns, localUnwatchFns);
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Handles the general case of an `if` / `else if` / ... / `else` chain (three or more branches).
|
|
482
|
+
*
|
|
483
|
+
* Iterates through the branches in order and activates the first one whose condition is
|
|
484
|
+
* true; a branch without a condition is always considered valid and acts as the final
|
|
485
|
+
* `else`. The state is set to the index of the activated branch.
|
|
486
|
+
*
|
|
487
|
+
* @param blocks - Ordered list of conditional branches to evaluate.
|
|
488
|
+
* @param state - The current state (index of the active branch, or `null` if none).
|
|
489
|
+
* @param unwatchFns - Shared array of active cleanup functions.
|
|
490
|
+
* @param localUnwatchFns - Cleanup functions generated by the last branch activation.
|
|
491
|
+
* @returns The new state and new cleanup functions if the active branch changed,
|
|
492
|
+
* otherwise `undefined`. Also returns `undefined` if no branch matches.
|
|
493
|
+
*/
|
|
494
|
+
function handleIfElseIf(blocks, state, unwatchFns, localUnwatchFns) {
|
|
495
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
496
|
+
const { condition, block } = blocks[i];
|
|
497
|
+
if (!condition || condition()) return checkAndUpdateState(state, i, block, unwatchFns, localUnwatchFns);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Updates the conditional structure state only when the active branch changes.
|
|
502
|
+
*
|
|
503
|
+
* If `newState` differs from `state`:
|
|
504
|
+
* 1. runs cleanup of the previous branch's functions (see {@link unwatch});
|
|
505
|
+
* 2. executes the new branch's block via {@link Signal.subtle.untrack} to avoid
|
|
506
|
+
* creating unwanted reactive dependencies during block execution;
|
|
507
|
+
* 3. registers the new cleanup functions in the shared `unwatchFns` array.
|
|
508
|
+
*
|
|
509
|
+
* If the branch has not changed, no operation is performed.
|
|
510
|
+
*
|
|
511
|
+
* @param state - The current state (index of the active branch, or `null` if none).
|
|
512
|
+
* @param newState - The new state to set (index of the branch to activate, or `null`).
|
|
513
|
+
* @param conditionalBlockFn - Branch function to execute, which returns its own
|
|
514
|
+
* cleanup functions.
|
|
515
|
+
* @param unwatchFns - Shared array of active cleanup functions.
|
|
516
|
+
* @param localUnwatchFns - Cleanup functions of the currently active branch, to be
|
|
517
|
+
* removed before activating the new branch.
|
|
518
|
+
* @returns Il nuovo stato e le nuove funzioni di cleanup se il ramo è cambiato, altrimenti
|
|
519
|
+
* `undefined`.
|
|
520
|
+
*/
|
|
521
|
+
function checkAndUpdateState(state, newState, conditionalBlockFn, unwatchFns, localUnwatchFns) {
|
|
522
|
+
if (state !== newState) {
|
|
523
|
+
unwatch(unwatchFns, localUnwatchFns);
|
|
524
|
+
localUnwatchFns = Signal.subtle.untrack(conditionalBlockFn);
|
|
525
|
+
unwatchFns.push(...localUnwatchFns);
|
|
526
|
+
return {
|
|
527
|
+
state: newState,
|
|
528
|
+
fns: localUnwatchFns
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Executes and removes the cleanup functions of the previously active branch.
|
|
534
|
+
*
|
|
535
|
+
* For each local function: removes it from the shared `unwatchFns` array (if present)
|
|
536
|
+
* and then invokes it to release resources / tear down associated subscriptions.
|
|
537
|
+
*
|
|
538
|
+
* @param unwatchFns - Shared array of active cleanup functions, mutated in place.
|
|
539
|
+
* @param localUnwatchFns - Cleanup functions of the branch to deactivate.
|
|
540
|
+
*/
|
|
541
|
+
function unwatch(unwatchFns, localUnwatchFns) {
|
|
542
|
+
for (const fn of localUnwatchFns) {
|
|
543
|
+
const index = unwatchFns.indexOf(fn);
|
|
544
|
+
if (index !== -1) unwatchFns.splice(index, 1);
|
|
545
|
+
fn();
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region ../packages/core/src/utils/for.utils.ts
|
|
550
|
+
/**
|
|
551
|
+
* Reactively iterates over a list of items, re-running the loop whenever the tracked condition changes.
|
|
552
|
+
* Previous iteration side-effects are cleaned up before each re-evaluation.
|
|
553
|
+
*
|
|
554
|
+
* @param unwatchFns - Array collecting cleanup functions for the parent scope.
|
|
555
|
+
* @param condition - A reactive function that returns the array of items to iterate over.
|
|
556
|
+
* @param forFn - A callback invoked for each item, receiving the item and its index. Must return an array of cleanup functions.
|
|
557
|
+
*/
|
|
558
|
+
function _for(unwatchFns, condition, forFn) {
|
|
559
|
+
const localUnwatchFns = new Array();
|
|
560
|
+
const unlistener = effect(() => {
|
|
561
|
+
unwatch(unwatchFns, localUnwatchFns);
|
|
562
|
+
const items = condition();
|
|
563
|
+
Signal.subtle.untrack(() => {
|
|
564
|
+
for (let i = 0; i < items.length; i++) {
|
|
565
|
+
localUnwatchFns.push(...forFn(items[i], i));
|
|
566
|
+
unwatchFns.push(...localUnwatchFns);
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
unwatchFns.push(unlistener);
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Builds a record of iteration context variables for a given index in the loop.
|
|
574
|
+
* Provides the current item, index, and convenience flags (`$first`, `$last`, `$even`, `$odd`).
|
|
575
|
+
*
|
|
576
|
+
* @param items - The full array being iterated.
|
|
577
|
+
* @param index - The current iteration index.
|
|
578
|
+
* @param itemAlias - The template alias name for the current item.
|
|
579
|
+
* @param indexAlias - The template alias name for the current index.
|
|
580
|
+
* @returns A record mapping alias names and built-in variables to their values.
|
|
581
|
+
*/
|
|
582
|
+
function _iterationVariables(items, index, itemAlias, indexAlias) {
|
|
583
|
+
const even = index % 2 === 0;
|
|
584
|
+
return {
|
|
585
|
+
[itemAlias]: items[index],
|
|
586
|
+
[indexAlias]: index,
|
|
587
|
+
$first: index === 0,
|
|
588
|
+
$last: index === items.length - 1,
|
|
589
|
+
$even: even,
|
|
590
|
+
$odd: !even
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
//#endregion
|
|
594
|
+
//#region ../packages/core/src/utils/switch.utils.ts
|
|
595
|
+
/**
|
|
596
|
+
* Creates a reactive switch/case structure by converting it into an if/else-if chain
|
|
597
|
+
* and delegating to {@link _if}.
|
|
598
|
+
*
|
|
599
|
+
* Each case block's condition values are compared against the result of the
|
|
600
|
+
* `expression` function using strict equality (`===`). A block with
|
|
601
|
+
* `condition: null` acts as the `default` branch (mapped to the `else` branch
|
|
602
|
+
* in the underlying if/else-if chain). Multiple values per case are supported
|
|
603
|
+
* (e.g. fall-through cases) and matched with `Array.some`.
|
|
604
|
+
*
|
|
605
|
+
* Because it delegates to `_if`, the switch benefits from the same optimisation:
|
|
606
|
+
* the active branch is only re-rendered when it actually changes.
|
|
607
|
+
*
|
|
608
|
+
* @param unwatchFns - Shared array that collects all active cleanup functions.
|
|
609
|
+
* Mutated in place by the underlying {@link _if} call.
|
|
610
|
+
* @param expression - Function that evaluates the switch expression. Called
|
|
611
|
+
* reactively inside an effect so that signal reads are tracked.
|
|
612
|
+
* @param blocks - Ordered list of case branches. Each entry contains:
|
|
613
|
+
* - `condition`: array of values to match against the expression result,
|
|
614
|
+
* or `null` for the default branch.
|
|
615
|
+
* - `block`: function that applies the branch's side effects and returns
|
|
616
|
+
* its cleanup functions.
|
|
617
|
+
*/
|
|
618
|
+
function _switch(unwatchFns, expression, blocks) {
|
|
619
|
+
_if(unwatchFns, blocks.map(({ condition, block }) => ({
|
|
620
|
+
condition: condition ? () => condition.some((condition) => condition === expression()) : void 0,
|
|
621
|
+
block
|
|
622
|
+
})));
|
|
623
|
+
}
|
|
624
|
+
//#endregion
|
|
625
|
+
export { BaseWebComponent, Event, Property, WebComponent, _for, _if, _iterationVariables, _switch, computed, effect, input, signal, unwatch };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaendar/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"description": "A library containing core utils such as webcomponent base classes and theming support",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@xaendar/signals": "0.6.
|
|
20
|
-
"@xaendar/types": "0.6.
|
|
19
|
+
"@xaendar/signals": "0.6.6",
|
|
20
|
+
"@xaendar/types": "0.6.6"
|
|
21
21
|
}
|
|
22
22
|
}
|