@xaendar/core 0.6.9 → 0.6.11
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 +90 -18
- package/dist/xaendar-core.es.js +218 -97
- package/package.json +3 -3
|
@@ -19,10 +19,11 @@ import { VoidFunction as VoidFunction_2 } from '@xaendar/types';
|
|
|
19
19
|
* It won't appear by intellisense but it's there.
|
|
20
20
|
*/
|
|
21
21
|
export declare class BaseWebComponent extends HTMLElement {
|
|
22
|
+
[key: string]: unknown;
|
|
22
23
|
/**
|
|
23
24
|
* Array of functions to unwatch all the signals used in the component
|
|
24
25
|
*/
|
|
25
|
-
protected
|
|
26
|
+
protected context: Context;
|
|
26
27
|
/**
|
|
27
28
|
* The root of the Web Component, where the content is rendered
|
|
28
29
|
*/
|
|
@@ -75,7 +76,7 @@ export declare type BaseWebComponentConstructor = Constructor<BaseWebComponent,
|
|
|
75
76
|
*/
|
|
76
77
|
declare type Block = {
|
|
77
78
|
condition?: NoArgsFunction<boolean>;
|
|
78
|
-
block: Function_2<[HTMLElement],
|
|
79
|
+
block: Function_2<[HTMLElement, Context], Context>;
|
|
79
80
|
};
|
|
80
81
|
|
|
81
82
|
/**
|
|
@@ -108,6 +109,55 @@ export declare type Computed<Value = any> = Signal.Computed<Value> & {
|
|
|
108
109
|
*/
|
|
109
110
|
export declare function computed<Value = any>(value: Value, options?: SignalOptions<Value>): Computed<Value>;
|
|
110
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Tracks identifier scope during run time template function execution
|
|
114
|
+
* Each `Context` instance represents one lexical scope (e.g. a `@for` loop body)
|
|
115
|
+
* and can be chained to a parent context for outer-scope resolution.
|
|
116
|
+
*/
|
|
117
|
+
export declare class Context {
|
|
118
|
+
private _root;
|
|
119
|
+
private _parent;
|
|
120
|
+
private _identifiers;
|
|
121
|
+
/**
|
|
122
|
+
* Array of functions to be called when the current context is destroyed (e.g. a `@if` becomes false)
|
|
123
|
+
* These functions contains
|
|
124
|
+
* - Remove Element
|
|
125
|
+
* - Remove EventListener
|
|
126
|
+
* - Effect unsubscription Function
|
|
127
|
+
*/
|
|
128
|
+
private _unwatchFns;
|
|
129
|
+
private _children;
|
|
130
|
+
private _nodes;
|
|
131
|
+
/**
|
|
132
|
+
* Creates a new scope context.
|
|
133
|
+
*
|
|
134
|
+
* @param _root - Web Component Reference to access properties and methods directly for bindings
|
|
135
|
+
* @param _parent Optional parent context representing the enclosing scope.
|
|
136
|
+
* @param _identifiers List of loop variable names declared in this scope.
|
|
137
|
+
*/
|
|
138
|
+
constructor(_root: BaseWebComponent, _parent: Context, _identifiers?: Map<string, ContextIdentifier>);
|
|
139
|
+
addIdentifier(name: string, valueFn: NoArgsFunction<unknown>): void;
|
|
140
|
+
/**
|
|
141
|
+
* Returns the innermost identifier in the current scope chain, or
|
|
142
|
+
* delegates to the parent context if none is found in this scope.
|
|
143
|
+
*
|
|
144
|
+
* @returns The most recently declared identifier name, or `undefined` if none exists.
|
|
145
|
+
*/
|
|
146
|
+
getIdentifier<ReturnType = unknown>(name: string): ContextIdentifier<ReturnType> | undefined;
|
|
147
|
+
getEventHandler(handler: string): VoidFunction;
|
|
148
|
+
addChild(context: Context): void;
|
|
149
|
+
removeChild(context: Context): void;
|
|
150
|
+
addNode(node: Node): void;
|
|
151
|
+
removeNode(nodeToRemove: Node): void;
|
|
152
|
+
listen(...fns: NoArgsVoidFunction[]): void;
|
|
153
|
+
unlisten(): void;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
declare type ContextIdentifier<ReturnType = unknown> = {
|
|
157
|
+
get: NoArgsFunction<ReturnType>;
|
|
158
|
+
reactive: boolean;
|
|
159
|
+
};
|
|
160
|
+
|
|
111
161
|
/**
|
|
112
162
|
* Runs a side-effectful function and automatically re-runs it whenever any
|
|
113
163
|
* Signal read during its execution changes.
|
|
@@ -158,11 +208,11 @@ export declare type EventOptions = Beautify<RequireOne<Omit<CustomEventInit, 'de
|
|
|
158
208
|
* Previous iteration side-effects are cleaned up before each re-evaluation.
|
|
159
209
|
*
|
|
160
210
|
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
161
|
-
* @param
|
|
211
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
162
212
|
* @param condition - A reactive function that returns the array of items to iterate over.
|
|
163
213
|
* @param forFn - A callback invoked for each item, receiving the parent node, the item, and its index. Must return an array of cleanup functions.
|
|
164
214
|
*/
|
|
165
|
-
export declare function _for(parentNode: HTMLElement,
|
|
215
|
+
export declare function _for(parentNode: HTMLElement, parentContext: Context, condition: () => unknown[], forFn: Function_2<[parentNode: HTMLElement, context: Context, item: unknown, index: number], Context>): void;
|
|
166
216
|
|
|
167
217
|
/**
|
|
168
218
|
* Creates a reactive conditional structure from a list of branches.
|
|
@@ -179,12 +229,13 @@ export declare function _for(parentNode: HTMLElement, unwatchFns: NoArgsVoidFunc
|
|
|
179
229
|
* the active branch has actually changed.
|
|
180
230
|
*
|
|
181
231
|
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
232
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
182
233
|
* @param unwatchFns - Shared array that collects all active cleanup functions.
|
|
183
234
|
* Mutated in place: the created effect and branch functions are added to and
|
|
184
235
|
* removed from this array.
|
|
185
236
|
* @param blocks - Ordered list of conditional branches to evaluate.
|
|
186
237
|
*/
|
|
187
|
-
export declare function _if(parentNode: HTMLElement,
|
|
238
|
+
export declare function _if(parentNode: HTMLElement, parentContext: Context, blocks: Block[]): void;
|
|
188
239
|
|
|
189
240
|
/**
|
|
190
241
|
* An `InputSignal` is a specialized `Signal.State` designed for use as a property signal in web components.
|
|
@@ -315,6 +366,37 @@ declare type PropertyDecoratorOptionsWithRequired<ActualValue = unknown, Incomin
|
|
|
315
366
|
required: true;
|
|
316
367
|
};
|
|
317
368
|
|
|
369
|
+
export declare function _renderElement(parentNode: HTMLElement, context: Context, tagName: string, attributes: RenderElementAttribute[], events: RenderElementEvent[]): void;
|
|
370
|
+
|
|
371
|
+
declare type RenderElementAttribute = {
|
|
372
|
+
name: string;
|
|
373
|
+
value: string;
|
|
374
|
+
literal: boolean;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
declare type RenderElementEvent = {
|
|
378
|
+
name: string;
|
|
379
|
+
handler: string;
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
*
|
|
384
|
+
* @param parentNode
|
|
385
|
+
* @param text
|
|
386
|
+
* @param context
|
|
387
|
+
* @returns
|
|
388
|
+
*/
|
|
389
|
+
export declare function _renderLiteralText(parentNode: HTMLElement, context: Context, text: string): void;
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
*
|
|
393
|
+
* @param parentNode
|
|
394
|
+
* @param text
|
|
395
|
+
* @param context
|
|
396
|
+
* @returns
|
|
397
|
+
*/
|
|
398
|
+
export declare function _renderText(parentNode: HTMLElement, context: Context, text: string): void;
|
|
399
|
+
|
|
318
400
|
/**
|
|
319
401
|
* Creates a writable reactive signal.
|
|
320
402
|
*
|
|
@@ -367,6 +449,7 @@ export { Signal_2 as Signal }
|
|
|
367
449
|
* the active branch is only re-rendered when it actually changes.
|
|
368
450
|
*
|
|
369
451
|
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
452
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
370
453
|
* @param unwatchFns - Shared array that collects all active cleanup functions.
|
|
371
454
|
* Mutated in place by the underlying {@link _if} call.
|
|
372
455
|
* @param expression - Function that evaluates the switch expression. Called
|
|
@@ -377,22 +460,11 @@ export { Signal_2 as Signal }
|
|
|
377
460
|
* - `block`: function that applies the branch's side effects and returns
|
|
378
461
|
* its cleanup functions.
|
|
379
462
|
*/
|
|
380
|
-
export declare function _switch(parentNode: HTMLElement,
|
|
463
|
+
export declare function _switch(parentNode: HTMLElement, parentContext: Context, expression: NoArgsFunction<unknown>, blocks: Array<{
|
|
381
464
|
condition: unknown[] | null;
|
|
382
|
-
block:
|
|
465
|
+
block: Function_2<[HTMLElement, Context], Context>;
|
|
383
466
|
}>): void;
|
|
384
467
|
|
|
385
|
-
/**
|
|
386
|
-
* Executes and removes the cleanup functions of the previously active branch.
|
|
387
|
-
*
|
|
388
|
-
* For each local function: removes it from the shared `unwatchFns` array (if present)
|
|
389
|
-
* and then invokes it to release resources / tear down associated subscriptions.
|
|
390
|
-
*
|
|
391
|
-
* @param unwatchFns - Shared array of active cleanup functions, mutated in place.
|
|
392
|
-
* @param localUnwatchFns - Cleanup functions of the branch to deactivate.
|
|
393
|
-
*/
|
|
394
|
-
export declare function unwatch(unwatchFns: NoArgsVoidFunction[], localUnwatchFns: NoArgsVoidFunction[]): void;
|
|
395
|
-
|
|
396
468
|
/**
|
|
397
469
|
* Decorator to define a web component
|
|
398
470
|
* @param selector Name or names of the custom element
|
package/dist/xaendar-core.es.js
CHANGED
|
@@ -215,7 +215,7 @@ var BaseWebComponent = class extends HTMLElement {
|
|
|
215
215
|
/**
|
|
216
216
|
* Array of functions to unwatch all the signals used in the component
|
|
217
217
|
*/
|
|
218
|
-
|
|
218
|
+
context;
|
|
219
219
|
/**
|
|
220
220
|
* The root of the Web Component, where the content is rendered
|
|
221
221
|
*/
|
|
@@ -269,8 +269,7 @@ var BaseWebComponent = class extends HTMLElement {
|
|
|
269
269
|
* the properties initialization won't call the render method
|
|
270
270
|
*/
|
|
271
271
|
disconnectedCallback() {
|
|
272
|
-
this.
|
|
273
|
-
this.unwatchFns = [];
|
|
272
|
+
this.context.unlisten();
|
|
274
273
|
}
|
|
275
274
|
};
|
|
276
275
|
//#endregion
|
|
@@ -401,7 +400,137 @@ function signal(value, options) {
|
|
|
401
400
|
return getter;
|
|
402
401
|
}
|
|
403
402
|
//#endregion
|
|
404
|
-
//#region ../packages/core/src/utils/
|
|
403
|
+
//#region ../packages/core/src/utils/context.util.ts
|
|
404
|
+
/**
|
|
405
|
+
* Tracks identifier scope during run time template function execution
|
|
406
|
+
* Each `Context` instance represents one lexical scope (e.g. a `@for` loop body)
|
|
407
|
+
* and can be chained to a parent context for outer-scope resolution.
|
|
408
|
+
*/
|
|
409
|
+
var Context = class {
|
|
410
|
+
_root;
|
|
411
|
+
_parent;
|
|
412
|
+
_identifiers;
|
|
413
|
+
/**
|
|
414
|
+
* Array of functions to be called when the current context is destroyed (e.g. a `@if` becomes false)
|
|
415
|
+
* These functions contains
|
|
416
|
+
* - Remove Element
|
|
417
|
+
* - Remove EventListener
|
|
418
|
+
* - Effect unsubscription Function
|
|
419
|
+
*/
|
|
420
|
+
_unwatchFns = new Array();
|
|
421
|
+
_children = new Array();
|
|
422
|
+
_nodes = new Array();
|
|
423
|
+
/**
|
|
424
|
+
* Creates a new scope context.
|
|
425
|
+
*
|
|
426
|
+
* @param _root - Web Component Reference to access properties and methods directly for bindings
|
|
427
|
+
* @param _parent Optional parent context representing the enclosing scope.
|
|
428
|
+
* @param _identifiers List of loop variable names declared in this scope.
|
|
429
|
+
*/
|
|
430
|
+
constructor(_root, _parent, _identifiers = /* @__PURE__ */ new Map()) {
|
|
431
|
+
this._root = _root;
|
|
432
|
+
this._parent = _parent;
|
|
433
|
+
this._identifiers = _identifiers;
|
|
434
|
+
}
|
|
435
|
+
addIdentifier(name, valueFn) {
|
|
436
|
+
if (this.getIdentifier(name)) throw new Error(`Identifier "${name}" is already declared in this scope.`);
|
|
437
|
+
this._identifiers.set(name, {
|
|
438
|
+
get: valueFn,
|
|
439
|
+
reactive: true
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Returns the innermost identifier in the current scope chain, or
|
|
444
|
+
* delegates to the parent context if none is found in this scope.
|
|
445
|
+
*
|
|
446
|
+
* @returns The most recently declared identifier name, or `undefined` if none exists.
|
|
447
|
+
*/
|
|
448
|
+
getIdentifier(name) {
|
|
449
|
+
if (this._identifiers.has(name)) return this._identifiers.get(name);
|
|
450
|
+
if (this._parent) return this._parent.getIdentifier(name);
|
|
451
|
+
return {
|
|
452
|
+
get: () => this._root[name],
|
|
453
|
+
reactive: true
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
getEventHandler(handler) {
|
|
457
|
+
return this._root[handler];
|
|
458
|
+
}
|
|
459
|
+
addChild(context) {
|
|
460
|
+
this._children.push(context);
|
|
461
|
+
}
|
|
462
|
+
removeChild(context) {
|
|
463
|
+
this._children = this._children.filter((child) => child === context);
|
|
464
|
+
}
|
|
465
|
+
addNode(node) {
|
|
466
|
+
this._nodes.push(node);
|
|
467
|
+
}
|
|
468
|
+
removeNode(nodeToRemove) {
|
|
469
|
+
this._nodes = this._nodes.filter((node) => node === nodeToRemove);
|
|
470
|
+
}
|
|
471
|
+
listen(...fns) {
|
|
472
|
+
this._unwatchFns.push(...fns);
|
|
473
|
+
}
|
|
474
|
+
unlisten() {
|
|
475
|
+
this._unwatchFns.forEach((fn) => fn());
|
|
476
|
+
this._children.forEach((child) => child.unlisten());
|
|
477
|
+
this._unwatchFns = [];
|
|
478
|
+
this._nodes = [];
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region ../packages/core/src/utils/for.util.ts
|
|
483
|
+
/**
|
|
484
|
+
* Reactively iterates over a list of items, re-running the loop whenever the tracked condition changes.
|
|
485
|
+
* Previous iteration side-effects are cleaned up before each re-evaluation.
|
|
486
|
+
*
|
|
487
|
+
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
488
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
489
|
+
* @param condition - A reactive function that returns the array of items to iterate over.
|
|
490
|
+
* @param forFn - A callback invoked for each item, receiving the parent node, the item, and its index. Must return an array of cleanup functions.
|
|
491
|
+
*/
|
|
492
|
+
function _for(parentNode, parentContext, condition, forFn) {
|
|
493
|
+
let contexts = new Array();
|
|
494
|
+
const unlistener = effect(() => {
|
|
495
|
+
contexts.forEach((context) => {
|
|
496
|
+
context.unlisten();
|
|
497
|
+
parentContext.removeChild(context);
|
|
498
|
+
});
|
|
499
|
+
contexts = [];
|
|
500
|
+
const items = condition();
|
|
501
|
+
Signal.subtle.untrack(() => {
|
|
502
|
+
for (let i = 0; i < items.length; i++) {
|
|
503
|
+
const context = forFn(parentNode, parentContext, items[i], i);
|
|
504
|
+
contexts.push(context);
|
|
505
|
+
parentContext.addChild(context);
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
parentContext.listen(unlistener);
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Builds a record of iteration context variables for a given index in the loop.
|
|
513
|
+
* Provides the current item, index, and convenience flags (`$first`, `$last`, `$even`, `$odd`).
|
|
514
|
+
*
|
|
515
|
+
* @param items - The full array being iterated.
|
|
516
|
+
* @param index - The current iteration index.
|
|
517
|
+
* @param itemAlias - The template alias name for the current item.
|
|
518
|
+
* @param indexAlias - The template alias name for the current index.
|
|
519
|
+
* @returns A record mapping alias names and built-in variables to their values.
|
|
520
|
+
*/
|
|
521
|
+
function _iterationVariables(items, index, itemAlias, indexAlias) {
|
|
522
|
+
const even = index % 2 === 0;
|
|
523
|
+
return {
|
|
524
|
+
[itemAlias]: items[index],
|
|
525
|
+
[indexAlias]: index,
|
|
526
|
+
$first: index === 0,
|
|
527
|
+
$last: index === items.length - 1,
|
|
528
|
+
$even: even,
|
|
529
|
+
$odd: !even
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
//#endregion
|
|
533
|
+
//#region ../packages/core/src/utils/if.util.ts
|
|
405
534
|
/**
|
|
406
535
|
* Creates a reactive conditional structure from a list of branches.
|
|
407
536
|
*
|
|
@@ -417,32 +546,33 @@ function signal(value, options) {
|
|
|
417
546
|
* the active branch has actually changed.
|
|
418
547
|
*
|
|
419
548
|
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
549
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
420
550
|
* @param unwatchFns - Shared array that collects all active cleanup functions.
|
|
421
551
|
* Mutated in place: the created effect and branch functions are added to and
|
|
422
552
|
* removed from this array.
|
|
423
553
|
* @param blocks - Ordered list of conditional branches to evaluate.
|
|
424
554
|
*/
|
|
425
|
-
function _if(parentNode,
|
|
426
|
-
let state
|
|
427
|
-
let localUnwatchFns = new Array();
|
|
555
|
+
function _if(parentNode, parentContext, blocks) {
|
|
556
|
+
let state;
|
|
428
557
|
let fn;
|
|
429
558
|
switch (blocks.length) {
|
|
430
559
|
case 1:
|
|
431
|
-
fn = () => handleIf(parentNode, blocks[0], state
|
|
560
|
+
fn = (state) => handleIf(parentNode, parentContext, blocks[0], state);
|
|
432
561
|
break;
|
|
433
562
|
case 2:
|
|
434
|
-
fn = () => handleIfElse(parentNode, blocks[0], blocks[1], state
|
|
563
|
+
fn = (state) => handleIfElse(parentNode, parentContext, blocks[0], blocks[1], state);
|
|
435
564
|
break;
|
|
436
|
-
default: fn = () => handleIfElseIf(parentNode, blocks, state
|
|
565
|
+
default: fn = (state) => handleIfElseIf(parentNode, parentContext, blocks, state);
|
|
437
566
|
}
|
|
438
567
|
const unlistener = effect(() => {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
state
|
|
442
|
-
localUnwatchFns = retVal.fns;
|
|
568
|
+
if (state) {
|
|
569
|
+
state.context.unlisten();
|
|
570
|
+
parentContext.removeChild(state.context);
|
|
443
571
|
}
|
|
572
|
+
state = fn(state);
|
|
573
|
+
if (state) parentContext.addChild(state.context);
|
|
444
574
|
});
|
|
445
|
-
|
|
575
|
+
parentContext.listen(unlistener);
|
|
446
576
|
}
|
|
447
577
|
/**
|
|
448
578
|
* Handles the simple `if` case (a single branch, no `else`).
|
|
@@ -451,32 +581,33 @@ function _if(parentNode, unwatchFns, blocks) {
|
|
|
451
581
|
* previously active branch is deactivated by resetting the state to `null` and
|
|
452
582
|
* executing an empty block.
|
|
453
583
|
*
|
|
584
|
+
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
585
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
454
586
|
* @param ifBlock - The `if` branch to evaluate.
|
|
455
587
|
* @param state - The current state (index of the active branch, or `null` if none).
|
|
456
|
-
* @param unwatchFns - Shared array of active cleanup functions.
|
|
457
|
-
* @param localUnwatchFns - Cleanup functions generated by the last branch activation.
|
|
458
588
|
* @returns The new state and new cleanup functions if the active branch changed,
|
|
459
589
|
* otherwise `undefined`.
|
|
460
590
|
*/
|
|
461
|
-
function handleIf(parentNode, ifBlock, state
|
|
462
|
-
|
|
591
|
+
function handleIf(parentNode, parentContext, ifBlock, state) {
|
|
592
|
+
if (ifBlock.condition()) return checkAndUpdateState(parentNode, parentContext, state, 0, ifBlock.block);
|
|
593
|
+
else parentContext.unlisten();
|
|
463
594
|
}
|
|
464
595
|
/**
|
|
465
596
|
* Handles the `if` / `else` case (exactly two branches).
|
|
466
597
|
*
|
|
467
598
|
* If the `if` condition is true, the first branch is activated (state `0`); otherwise,
|
|
468
599
|
* the `else` branch is activated (state `1`).
|
|
469
|
-
*
|
|
600
|
+
*
|
|
601
|
+
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
602
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
470
603
|
* @param ifBlock - The `if` branch to evaluate.
|
|
471
604
|
* @param elseBlock - The `else` branch used when the `if` condition is false.
|
|
472
605
|
* @param state - The current state (index of the active branch, or `null` if none).
|
|
473
|
-
* @param unwatchFns - Shared array of active cleanup functions.
|
|
474
|
-
* @param localUnwatchFns - Cleanup functions generated by the last branch activation.
|
|
475
606
|
* @returns The new state and new cleanup functions if the active branch changed,
|
|
476
607
|
* otherwise `undefined`.
|
|
477
608
|
*/
|
|
478
|
-
function handleIfElse(parentNode, ifBlock, elseBlock, state
|
|
479
|
-
return ifBlock.condition() ? checkAndUpdateState(parentNode, state, 0, ifBlock.block
|
|
609
|
+
function handleIfElse(parentNode, parentContext, ifBlock, elseBlock, state) {
|
|
610
|
+
return ifBlock.condition() ? checkAndUpdateState(parentNode, parentContext, state, 0, ifBlock.block) : checkAndUpdateState(parentNode, parentContext, state, 1, elseBlock.block);
|
|
480
611
|
}
|
|
481
612
|
/**
|
|
482
613
|
* Handles the general case of an `if` / `else if` / ... / `else` chain (three or more branches).
|
|
@@ -484,18 +615,18 @@ function handleIfElse(parentNode, ifBlock, elseBlock, state, unwatchFns, localUn
|
|
|
484
615
|
* Iterates through the branches in order and activates the first one whose condition is
|
|
485
616
|
* true; a branch without a condition is always considered valid and acts as the final
|
|
486
617
|
* `else`. The state is set to the index of the activated branch.
|
|
487
|
-
*
|
|
618
|
+
*
|
|
619
|
+
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
620
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
488
621
|
* @param blocks - Ordered list of conditional branches to evaluate.
|
|
489
622
|
* @param state - The current state (index of the active branch, or `null` if none).
|
|
490
|
-
* @param unwatchFns - Shared array of active cleanup functions.
|
|
491
|
-
* @param localUnwatchFns - Cleanup functions generated by the last branch activation.
|
|
492
623
|
* @returns The new state and new cleanup functions if the active branch changed,
|
|
493
624
|
* otherwise `undefined`. Also returns `undefined` if no branch matches.
|
|
494
625
|
*/
|
|
495
|
-
function handleIfElseIf(parentNode, blocks, state
|
|
626
|
+
function handleIfElseIf(parentNode, parentContext, blocks, state) {
|
|
496
627
|
for (let i = 0; i < blocks.length; i++) {
|
|
497
628
|
const { condition, block } = blocks[i];
|
|
498
|
-
if (!condition || condition()) return checkAndUpdateState(parentNode, state, i, block
|
|
629
|
+
if (!condition || condition()) return checkAndUpdateState(parentNode, parentContext, state, i, block);
|
|
499
630
|
}
|
|
500
631
|
}
|
|
501
632
|
/**
|
|
@@ -509,91 +640,80 @@ function handleIfElseIf(parentNode, blocks, state, unwatchFns, localUnwatchFns)
|
|
|
509
640
|
*
|
|
510
641
|
* If the branch has not changed, no operation is performed.
|
|
511
642
|
*
|
|
643
|
+
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
644
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
512
645
|
* @param state - The current state (index of the active branch, or `null` if none).
|
|
513
646
|
* @param newState - The new state to set (index of the branch to activate, or `null`).
|
|
514
647
|
* @param conditionalBlockFn - Branch function to execute, which returns its own
|
|
515
648
|
* cleanup functions.
|
|
516
|
-
* @param unwatchFns - Shared array of active cleanup functions.
|
|
517
|
-
* @param localUnwatchFns - Cleanup functions of the currently active branch, to be
|
|
518
|
-
* removed before activating the new branch.
|
|
519
649
|
* @returns Il nuovo stato e le nuove funzioni di cleanup se il ramo è cambiato, altrimenti
|
|
520
650
|
* `undefined`.
|
|
521
651
|
*/
|
|
522
|
-
function checkAndUpdateState(parentNode, state, newState, conditionalBlockFn
|
|
523
|
-
if (state !== newState) {
|
|
524
|
-
|
|
525
|
-
localUnwatchFns = Signal.subtle.untrack(() => conditionalBlockFn(parentNode));
|
|
526
|
-
unwatchFns.push(...localUnwatchFns);
|
|
652
|
+
function checkAndUpdateState(parentNode, parentContext, state, newState, conditionalBlockFn) {
|
|
653
|
+
if (state?.activeBranch !== newState) {
|
|
654
|
+
state?.context.unlisten();
|
|
527
655
|
return {
|
|
528
|
-
|
|
529
|
-
|
|
656
|
+
activeBranch: newState,
|
|
657
|
+
context: Signal.subtle.untrack(() => conditionalBlockFn(parentNode, parentContext))
|
|
530
658
|
};
|
|
531
659
|
}
|
|
532
660
|
}
|
|
533
|
-
/**
|
|
534
|
-
* Executes and removes the cleanup functions of the previously active branch.
|
|
535
|
-
*
|
|
536
|
-
* For each local function: removes it from the shared `unwatchFns` array (if present)
|
|
537
|
-
* and then invokes it to release resources / tear down associated subscriptions.
|
|
538
|
-
*
|
|
539
|
-
* @param unwatchFns - Shared array of active cleanup functions, mutated in place.
|
|
540
|
-
* @param localUnwatchFns - Cleanup functions of the branch to deactivate.
|
|
541
|
-
*/
|
|
542
|
-
function unwatch(unwatchFns, localUnwatchFns) {
|
|
543
|
-
for (const fn of localUnwatchFns) {
|
|
544
|
-
const index = unwatchFns.indexOf(fn);
|
|
545
|
-
if (index !== -1) unwatchFns.splice(index, 1);
|
|
546
|
-
fn();
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
661
|
//#endregion
|
|
550
|
-
//#region ../packages/core/src/utils/
|
|
662
|
+
//#region ../packages/core/src/utils/render-text.util.ts
|
|
551
663
|
/**
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
* @param
|
|
556
|
-
* @
|
|
557
|
-
* @param condition - A reactive function that returns the array of items to iterate over.
|
|
558
|
-
* @param forFn - A callback invoked for each item, receiving the parent node, the item, and its index. Must return an array of cleanup functions.
|
|
664
|
+
*
|
|
665
|
+
* @param parentNode
|
|
666
|
+
* @param text
|
|
667
|
+
* @param context
|
|
668
|
+
* @returns
|
|
559
669
|
*/
|
|
560
|
-
function
|
|
561
|
-
const
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
localUnwatchFns.push(...forFn(parentNode, items[i], i));
|
|
568
|
-
unwatchFns.push(...localUnwatchFns);
|
|
569
|
-
}
|
|
570
|
-
});
|
|
670
|
+
function _renderText(parentNode, context, text) {
|
|
671
|
+
const identifier = context.getIdentifier(text);
|
|
672
|
+
const node = document.createTextNode(identifier.get());
|
|
673
|
+
parentNode.appendChild(node);
|
|
674
|
+
context.listen(() => {
|
|
675
|
+
context.removeNode(node);
|
|
676
|
+
parentNode.removeChild(node);
|
|
571
677
|
});
|
|
572
|
-
|
|
678
|
+
if (identifier.reactive) context.listen(effect(() => node.textContent = identifier.get()));
|
|
573
679
|
}
|
|
574
680
|
/**
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
* @param
|
|
579
|
-
* @
|
|
580
|
-
* @param itemAlias - The template alias name for the current item.
|
|
581
|
-
* @param indexAlias - The template alias name for the current index.
|
|
582
|
-
* @returns A record mapping alias names and built-in variables to their values.
|
|
681
|
+
*
|
|
682
|
+
* @param parentNode
|
|
683
|
+
* @param text
|
|
684
|
+
* @param context
|
|
685
|
+
* @returns
|
|
583
686
|
*/
|
|
584
|
-
function
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
687
|
+
function _renderLiteralText(parentNode, context, text) {
|
|
688
|
+
const node = document.createTextNode(text);
|
|
689
|
+
parentNode.appendChild(node);
|
|
690
|
+
context.listen(() => parentNode.removeChild(node));
|
|
691
|
+
}
|
|
692
|
+
//#endregion
|
|
693
|
+
//#region ../packages/core/src/utils/render-util.ts
|
|
694
|
+
function _renderElement(parentNode, context, tagName, attributes, events) {
|
|
695
|
+
const element = document.createElement(tagName);
|
|
696
|
+
parentNode.appendChild(element);
|
|
697
|
+
context.listen(() => {
|
|
698
|
+
context.removeNode(element);
|
|
699
|
+
parentNode.removeChild(element);
|
|
700
|
+
});
|
|
701
|
+
attributes.forEach(({ name, value, literal }) => {
|
|
702
|
+
if (literal) element.setAttribute(name, value);
|
|
703
|
+
else {
|
|
704
|
+
const identifier = context.getIdentifier(value);
|
|
705
|
+
identifier.reactive ? context.listen(effect(() => element.setAttribute(name, String(identifier.get())))) : element.setAttribute(name, String(identifier.get()));
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
events.forEach((event) => {
|
|
709
|
+
const handler = ($event) => context.getEventHandler(event.handler);
|
|
710
|
+
const name = event.name;
|
|
711
|
+
element.addEventListener(name, handler);
|
|
712
|
+
context.listen(() => element.removeEventListener(name, handler));
|
|
713
|
+
});
|
|
594
714
|
}
|
|
595
715
|
//#endregion
|
|
596
|
-
//#region ../packages/core/src/utils/switch.
|
|
716
|
+
//#region ../packages/core/src/utils/switch.util.ts
|
|
597
717
|
/**
|
|
598
718
|
* Creates a reactive switch/case structure by converting it into an if/else-if chain
|
|
599
719
|
* and delegating to {@link _if}.
|
|
@@ -608,6 +728,7 @@ function _iterationVariables(items, index, itemAlias, indexAlias) {
|
|
|
608
728
|
* the active branch is only re-rendered when it actually changes.
|
|
609
729
|
*
|
|
610
730
|
* @param parentNode - The parent HTML element where the conditional structure is applied.
|
|
731
|
+
* @param parentContext - The parent Context object containing all the variables definition from the Parent Closure
|
|
611
732
|
* @param unwatchFns - Shared array that collects all active cleanup functions.
|
|
612
733
|
* Mutated in place by the underlying {@link _if} call.
|
|
613
734
|
* @param expression - Function that evaluates the switch expression. Called
|
|
@@ -618,11 +739,11 @@ function _iterationVariables(items, index, itemAlias, indexAlias) {
|
|
|
618
739
|
* - `block`: function that applies the branch's side effects and returns
|
|
619
740
|
* its cleanup functions.
|
|
620
741
|
*/
|
|
621
|
-
function _switch(parentNode,
|
|
622
|
-
_if(parentNode,
|
|
742
|
+
function _switch(parentNode, parentContext, expression, blocks) {
|
|
743
|
+
_if(parentNode, parentContext, blocks.map(({ condition, block }) => ({
|
|
623
744
|
condition: condition ? () => condition.some((condition) => condition === expression()) : void 0,
|
|
624
745
|
block
|
|
625
746
|
})));
|
|
626
747
|
}
|
|
627
748
|
//#endregion
|
|
628
|
-
export { BaseWebComponent, Event, Property, WebComponent, _for, _if, _iterationVariables, _switch, computed, effect, input, signal
|
|
749
|
+
export { BaseWebComponent, Context, Event, Property, WebComponent, _for, _if, _iterationVariables, _renderElement, _renderLiteralText, _renderText, _switch, computed, effect, input, signal };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaendar/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.11",
|
|
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.11",
|
|
20
|
+
"@xaendar/types": "0.6.11"
|
|
21
21
|
}
|
|
22
22
|
}
|