@xaendar/core 0.9.22 → 0.9.24
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/signals.js +2 -7
- package/dist/xaendar-core.d.ts +0 -90
- package/dist/xaendar-core.js +16 -38
- package/package.json +4 -4
- package/dist/signals-C-55LNEj.cjs +0 -261
package/dist/signals.js
CHANGED
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.computed = require_signals.computed;
|
|
4
|
-
exports.effect = require_signals.effect;
|
|
5
|
-
exports.input = require_signals.input;
|
|
6
|
-
exports.signal = require_signals.signal;
|
|
7
|
-
exports.untracked = require_signals.untracked;
|
|
1
|
+
import { a as input, i as computed, n as signal, r as effect, t as untracked } from "./signals-CxEAdVoe.js";
|
|
2
|
+
export { computed, effect, input, signal, untracked };
|
package/dist/xaendar-core.d.ts
CHANGED
|
@@ -2,11 +2,9 @@ import { AccessorDecorator } from '@xaendar/types';
|
|
|
2
2
|
import { Beautify } from '@xaendar/types';
|
|
3
3
|
import { ClassDecorator as ClassDecorator_2 } from '@xaendar/types';
|
|
4
4
|
import { Constructor } from '@xaendar/types';
|
|
5
|
-
import { EffectOptions } from '@xaendar/signals';
|
|
6
5
|
import { Function as Function_2 } from '@xaendar/types';
|
|
7
6
|
import { NoArgsFunction } from '@xaendar/types';
|
|
8
7
|
import { NoArgsVoidFunction } from '@xaendar/types';
|
|
9
|
-
import { NoArgsVoidFunction as NoArgsVoidFunction_2 } from '@xaendar/types';
|
|
10
8
|
import { RequireOne } from '@xaendar/types';
|
|
11
9
|
import { SignalOptions } from '@xaendar/signals';
|
|
12
10
|
import { VoidFunction as VoidFunction_2 } from '@xaendar/types';
|
|
@@ -105,19 +103,6 @@ export declare type Computed<Value = any> = Signal.Computed<Value> & {
|
|
|
105
103
|
(): Value;
|
|
106
104
|
};
|
|
107
105
|
|
|
108
|
-
/**
|
|
109
|
-
* Creates a read-only computed signal whose value is derived from other signals.
|
|
110
|
-
*
|
|
111
|
-
* Returns a callable getter that reads the current value, augmented with the
|
|
112
|
-
* underlying {@link Signal.State} API.
|
|
113
|
-
*
|
|
114
|
-
* @template Value - The type of the computed value. Defaults to `any`.
|
|
115
|
-
* @param value - The initial (seed) value of the computed signal.
|
|
116
|
-
* @param options - Configuration options for the underlying signal.
|
|
117
|
-
* @returns A {@link Computed} instance.
|
|
118
|
-
*/
|
|
119
|
-
export declare function computed<Value = any>(value: Value, options?: SignalOptions<Value>): Computed<Value>;
|
|
120
|
-
|
|
121
106
|
/**
|
|
122
107
|
* Tracks identifier scope during run time template function execution
|
|
123
108
|
* Each `Context` instance represents one lexical scope (e.g. a `@for` loop body)
|
|
@@ -275,43 +260,6 @@ export declare function createMATHMLElement(tagName: string): MathMLElement;
|
|
|
275
260
|
*/
|
|
276
261
|
export declare function createSVGElement(tagName: string): SVGElement;
|
|
277
262
|
|
|
278
|
-
/**
|
|
279
|
-
* Runs a side-effectful function and automatically re-runs it whenever any
|
|
280
|
-
* Signal read during its execution changes.
|
|
281
|
-
*
|
|
282
|
-
* Internally, `effect` wraps the user callback inside a `Computed` node
|
|
283
|
-
* (for dependency tracking) and observes it with a `Watcher` (for push
|
|
284
|
-
* notifications). When any tracked dependency changes, the `Watcher`
|
|
285
|
-
* schedules a microtask that re-evaluates the `Computed`, which in turn
|
|
286
|
-
* re-runs the user callback and re-registers the new set of dependencies.
|
|
287
|
-
*
|
|
288
|
-
* The returned disposer function stops the effect: it unwatches the internal
|
|
289
|
-
* `Computed` from the `Watcher`, severing all dependency subscriptions so
|
|
290
|
-
* the callback is never called again and the graph nodes can be
|
|
291
|
-
* garbage-collected.
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* ```ts
|
|
295
|
-
* const count = new State(0);
|
|
296
|
-
*
|
|
297
|
-
* const stop = effect(() => {
|
|
298
|
-
* console.log('count is', count.get());
|
|
299
|
-
* });
|
|
300
|
-
* // logs: "count is 0"
|
|
301
|
-
*
|
|
302
|
-
* count.set(1); // logs: "count is 1"
|
|
303
|
-
* count.set(2); // logs: "count is 2"
|
|
304
|
-
*
|
|
305
|
-
* stop(); // no more logs
|
|
306
|
-
* count.set(3); // silent
|
|
307
|
-
* ```
|
|
308
|
-
*
|
|
309
|
-
* @param fn - The side-effectful function to run. Any Signal read inside it
|
|
310
|
-
* is tracked as a dependency.
|
|
311
|
-
* @returns A disposer function that, when called, permanently stops the effect.
|
|
312
|
-
*/
|
|
313
|
-
export declare function effect(fn: NoArgsVoidFunction_2, options?: EffectOptions): NoArgsVoidFunction_2;
|
|
314
|
-
|
|
315
263
|
/**
|
|
316
264
|
* Decorator that declares a custom event output on a web component.
|
|
317
265
|
*
|
|
@@ -386,23 +334,6 @@ declare type ForKey = string | number;
|
|
|
386
334
|
*/
|
|
387
335
|
export declare function _if(parentNode: HTMLElement, parentContext: Context, blocks: Block[]): void;
|
|
388
336
|
|
|
389
|
-
/**
|
|
390
|
-
* Creates an `InputSignal` — a specialized reactive state designed for use
|
|
391
|
-
* as a property signal in web components.
|
|
392
|
-
*
|
|
393
|
-
* Unlike a plain `Signal.State`, the `set` method of an `InputSignal` is
|
|
394
|
-
* restricted to internal callers (identified by the private symbol) and
|
|
395
|
-
* accepts an optional `transform` function that converts incoming values
|
|
396
|
-
* (e.g. raw HTML attribute strings) into the internally stored type before
|
|
397
|
-
* updating the signal.
|
|
398
|
-
*
|
|
399
|
-
* @param value - The initial value of the signal.
|
|
400
|
-
* @param options - Optional configuration including an equality function,
|
|
401
|
-
* lifecycle hooks, and a `transform` function applied to incoming values.
|
|
402
|
-
* @returns A new `InputSignal` instance.
|
|
403
|
-
*/
|
|
404
|
-
export declare function input<ActualValue = unknown, IncomingValue = ActualValue>(value?: ActualValue, options?: InputSignalOptions<ActualValue, IncomingValue>): InputSignal<ActualValue, IncomingValue>;
|
|
405
|
-
|
|
406
337
|
/**
|
|
407
338
|
* A reactive value sourced from outside the component (e.g. an attribute).
|
|
408
339
|
*
|
|
@@ -651,20 +582,6 @@ export declare function _renderLiteralText(parentNode: HTMLElement, context: Con
|
|
|
651
582
|
*/
|
|
652
583
|
export declare function _renderText(parentNode: HTMLElement, context: Context, textFn: NoArgsFunction<string>): void;
|
|
653
584
|
|
|
654
|
-
/**
|
|
655
|
-
* Creates a writable reactive signal.
|
|
656
|
-
*
|
|
657
|
-
* Returns a callable getter that reads the current value, augmented with the
|
|
658
|
-
* underlying {@link Signal.State} API and an `update` method to derive the next
|
|
659
|
-
* value from the previous one.
|
|
660
|
-
*
|
|
661
|
-
* @template T - The type of the stored value. Defaults to `any`.
|
|
662
|
-
* @param value - The initial value of the signal.
|
|
663
|
-
* @param options - Configuration options for the signal.
|
|
664
|
-
* @returns A {@link SignalType} instance.
|
|
665
|
-
*/
|
|
666
|
-
export declare function signal<T = any>(value: T, options?: SignalOptions<T>): Signal_2<T>;
|
|
667
|
-
|
|
668
585
|
/**
|
|
669
586
|
* A writable reactive value.
|
|
670
587
|
*
|
|
@@ -717,13 +634,6 @@ export declare function _switch(parentNode: HTMLElement, parentContext: Context,
|
|
|
717
634
|
block: Function_2<[HTMLElement, Context, Node | null], Context>;
|
|
718
635
|
}>): void;
|
|
719
636
|
|
|
720
|
-
/**
|
|
721
|
-
* Executes a function without tracking any dependencies.
|
|
722
|
-
* @param fn - The function to execute without tracking.
|
|
723
|
-
* @returns The result of the function execution.
|
|
724
|
-
*/
|
|
725
|
-
export declare const untracked: typeof Signal.subtle.untrack;
|
|
726
|
-
|
|
727
637
|
/**
|
|
728
638
|
* Decorator that registers a class as a custom web component.
|
|
729
639
|
*
|
package/dist/xaendar-core.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const require_signals = require("./signals-C-55LNEj.cjs");
|
|
1
|
+
import { a as input, n as signal, o as INPUT_SIGNAL_SET_SYMBOL, r as effect, s as isInputSignal, t as untracked } from "./signals-CxEAdVoe.js";
|
|
3
2
|
//#region ../packages/core/src/decorators/event.decorator.ts
|
|
4
3
|
function isEventOptions(value) {
|
|
5
4
|
return !!value && typeof value === "object" && ("bubbles" in value || "cancelable" in value || "composed" in value);
|
|
@@ -80,7 +79,7 @@ function createPropertyDecorator(value, options) {
|
|
|
80
79
|
actualValue = value;
|
|
81
80
|
actualOptions = options;
|
|
82
81
|
} else actualOptions = value;
|
|
83
|
-
const signal =
|
|
82
|
+
const signal = input(actualValue, {
|
|
84
83
|
equals: actualOptions?.equals,
|
|
85
84
|
watched: actualOptions?.watched,
|
|
86
85
|
unwatched: actualOptions?.unwatched,
|
|
@@ -257,8 +256,8 @@ var BaseWebComponent = class extends HTMLElement {
|
|
|
257
256
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
258
257
|
const context = this;
|
|
259
258
|
if (!(name in context)) throw new Error(`Attribute ${name} is not associated to any property`);
|
|
260
|
-
if (!
|
|
261
|
-
context[name].set(newValue,
|
|
259
|
+
if (!isInputSignal(context[name])) throw new Error(`Property ${name} is not an InputSignal`);
|
|
260
|
+
context[name].set(newValue, INPUT_SIGNAL_SET_SYMBOL);
|
|
262
261
|
}
|
|
263
262
|
/**
|
|
264
263
|
* Called by the browser engine each time the element is inserted into the DOM.
|
|
@@ -502,11 +501,11 @@ function createAnchor(label, parentNode, context, referenceNode = null) {
|
|
|
502
501
|
function _for(parentNode, parentContext, condition, trackExpression, forFn) {
|
|
503
502
|
const anchor = createAnchor("for", parentNode, parentContext);
|
|
504
503
|
let entries = /* @__PURE__ */ new Map();
|
|
505
|
-
const unlistener =
|
|
504
|
+
const unlistener = effect(() => {
|
|
506
505
|
const items = condition();
|
|
507
506
|
const newKeys = items.map((item) => trackExpression(item));
|
|
508
507
|
const newKeySet = new Set(newKeys);
|
|
509
|
-
|
|
508
|
+
untracked(() => {
|
|
510
509
|
const newEntries = /* @__PURE__ */ new Map();
|
|
511
510
|
for (const [key, entry] of entries) if (!newKeySet.has(key)) {
|
|
512
511
|
entry.context.unlisten();
|
|
@@ -552,11 +551,11 @@ function _for(parentNode, parentContext, condition, trackExpression, forFn) {
|
|
|
552
551
|
* @returns A handle exposing the resolved variables and an `update` function.
|
|
553
552
|
*/
|
|
554
553
|
function _iterationVariables(context, items, index, itemName, aliases) {
|
|
555
|
-
const $index =
|
|
556
|
-
const $first =
|
|
557
|
-
const $last =
|
|
558
|
-
const $even =
|
|
559
|
-
const $odd =
|
|
554
|
+
const $index = signal(index);
|
|
555
|
+
const $first = signal(index === 0);
|
|
556
|
+
const $last = signal(index === items.length - 1);
|
|
557
|
+
const $even = signal(index % 2 === 0);
|
|
558
|
+
const $odd = signal(index % 2 !== 0);
|
|
560
559
|
const retVal = {
|
|
561
560
|
vars: {
|
|
562
561
|
[itemName]: items[index],
|
|
@@ -614,7 +613,7 @@ function _if(parentNode, parentContext, blocks) {
|
|
|
614
613
|
break;
|
|
615
614
|
default: fn = (state) => handleIfElseIf(parentNode, parentContext, blocks, state, anchor);
|
|
616
615
|
}
|
|
617
|
-
const unlistener =
|
|
616
|
+
const unlistener = effect(() => state = fn(state));
|
|
618
617
|
parentContext.listen(unlistener);
|
|
619
618
|
}
|
|
620
619
|
/**
|
|
@@ -698,7 +697,7 @@ function checkAndUpdateState(parentNode, parentContext, state, newState, conditi
|
|
|
698
697
|
state.context.unlisten();
|
|
699
698
|
parentContext.removeChild(state.context);
|
|
700
699
|
}
|
|
701
|
-
const context =
|
|
700
|
+
const context = untracked(() => conditionalBlockFn(parentNode, parentContext, anchor));
|
|
702
701
|
parentContext.addChild(context);
|
|
703
702
|
return {
|
|
704
703
|
activeBranch: newState,
|
|
@@ -746,7 +745,7 @@ function _renderElement(parentNode, context, anchor, tagName, attributes, events
|
|
|
746
745
|
mountNode(element, parentNode, context, anchor);
|
|
747
746
|
for (let i = 0; i < attributes.length; i++) {
|
|
748
747
|
const { name, value, reactive } = attributes[i];
|
|
749
|
-
reactive ? context.listen(
|
|
748
|
+
reactive ? context.listen(effect(() => element.setAttribute(name, String(value())))) : element.setAttribute(name, String(value()));
|
|
750
749
|
}
|
|
751
750
|
for (let i = 0; i < events.length; i++) {
|
|
752
751
|
const event = events[i];
|
|
@@ -800,7 +799,7 @@ function createMATHMLElement(tagName) {
|
|
|
800
799
|
function _renderText(parentNode, context, textFn) {
|
|
801
800
|
const node = document.createTextNode(textFn());
|
|
802
801
|
mountNode(node, parentNode, context);
|
|
803
|
-
context.listen(
|
|
802
|
+
context.listen(effect(() => node.textContent = textFn()));
|
|
804
803
|
}
|
|
805
804
|
/**
|
|
806
805
|
* Creates a static (non-reactive) text node with a literal string value.
|
|
@@ -848,25 +847,4 @@ function _switch(parentNode, parentContext, expression, blocks) {
|
|
|
848
847
|
})));
|
|
849
848
|
}
|
|
850
849
|
//#endregion
|
|
851
|
-
|
|
852
|
-
exports.Context = Context;
|
|
853
|
-
exports.Event = Event;
|
|
854
|
-
exports.Property = Property;
|
|
855
|
-
exports.WebComponent = WebComponent;
|
|
856
|
-
exports._for = _for;
|
|
857
|
-
exports._if = _if;
|
|
858
|
-
exports._iterationVariables = _iterationVariables;
|
|
859
|
-
exports._renderElement = _renderElement;
|
|
860
|
-
exports._renderLiteralText = _renderLiteralText;
|
|
861
|
-
exports._renderText = _renderText;
|
|
862
|
-
exports._switch = _switch;
|
|
863
|
-
exports.computed = require_signals.computed;
|
|
864
|
-
exports.createAnchor = createAnchor;
|
|
865
|
-
exports.createElement = createElement;
|
|
866
|
-
exports.createMATHMLElement = createMATHMLElement;
|
|
867
|
-
exports.createSVGElement = createSVGElement;
|
|
868
|
-
exports.effect = require_signals.effect;
|
|
869
|
-
exports.input = require_signals.input;
|
|
870
|
-
exports.mountNode = mountNode;
|
|
871
|
-
exports.signal = require_signals.signal;
|
|
872
|
-
exports.untracked = require_signals.untracked;
|
|
850
|
+
export { BaseWebComponent, Context, Event, Property, WebComponent, _for, _if, _iterationVariables, _renderElement, _renderLiteralText, _renderText, _switch, createAnchor, createElement, createMATHMLElement, createSVGElement, mountNode };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaendar/core",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.24",
|
|
4
4
|
"description": "A library containing core utils such as webcomponent base classes and theming support",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"default": "./dist/xaendar-core.js"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
|
-
"signals": {
|
|
17
|
+
"./signals": {
|
|
18
18
|
"import": {
|
|
19
19
|
"types": "./dist/signals.d.ts",
|
|
20
20
|
"default": "./dist/signals.js"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@xaendar/signals": "0.9.
|
|
26
|
-
"@xaendar/types": "0.9.
|
|
25
|
+
"@xaendar/signals": "0.9.24",
|
|
26
|
+
"@xaendar/types": "0.9.24"
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
//#region ../packages/core/src/signals/input/input-instance.symbol.ts
|
|
2
|
-
/**
|
|
3
|
-
* Unique symbol used to mark an object as a valid `InputSignal` instance.
|
|
4
|
-
*
|
|
5
|
-
* Set to `true` on every `InputSignal` created by the `input()` factory.
|
|
6
|
-
* Used by {@link isInputSignal} to distinguish input signals from plain
|
|
7
|
-
* `Signal.State` instances at runtime without exposing the marker in the
|
|
8
|
-
* public API.
|
|
9
|
-
*
|
|
10
|
-
* @internal
|
|
11
|
-
*/
|
|
12
|
-
var INPUT_SIGNAL_INSTANCE_SYMBOL = Symbol(`InputSignalInstance`);
|
|
13
|
-
/**
|
|
14
|
-
* Type guard that checks whether a given value is an `InputSignal` instance.
|
|
15
|
-
*
|
|
16
|
-
* Inspects the presence of {@link INPUT_SIGNAL_INSTANCE_SYMBOL} on the object,
|
|
17
|
-
* which is set to `true` by the `input()` factory for every valid instance.
|
|
18
|
-
*
|
|
19
|
-
* @param instance - The value to inspect.
|
|
20
|
-
* @returns `true` if `instance` is an `InputSignal`, `false` otherwise.
|
|
21
|
-
*/
|
|
22
|
-
function isInputSignal(instance) {
|
|
23
|
-
return instance?.[INPUT_SIGNAL_INSTANCE_SYMBOL];
|
|
24
|
-
}
|
|
25
|
-
//#endregion
|
|
26
|
-
//#region ../packages/core/src/signals/input/input-set.symbol.ts
|
|
27
|
-
/**
|
|
28
|
-
* This symbol is used to call the set method of the InputSignal
|
|
29
|
-
* Normally the set method is permitted internally and should not be called
|
|
30
|
-
* by the User
|
|
31
|
-
*/
|
|
32
|
-
var INPUT_SIGNAL_SET_SYMBOL = Symbol(`InputSignalSet`);
|
|
33
|
-
/**
|
|
34
|
-
* Asserts that the provided symbol matches the internal {@link INPUT_SIGNAL_SET_SYMBOL} symbol,
|
|
35
|
-
* ensuring the caller has access to internal APIs.
|
|
36
|
-
*
|
|
37
|
-
* Throws if the symbol does not match, preventing external code from
|
|
38
|
-
* invoking methods intended for internal use only.
|
|
39
|
-
*
|
|
40
|
-
* @param symbol - The symbol to validate against {@link INPUT_SIGNAL_SET_SYMBOL}.
|
|
41
|
-
* @throws {Error} If `symbol` does not match {@link INPUT_SIGNAL_SET_SYMBOL}.
|
|
42
|
-
* @internal
|
|
43
|
-
*/
|
|
44
|
-
function assertPrivateContext(symbol) {
|
|
45
|
-
if (symbol !== INPUT_SIGNAL_SET_SYMBOL) throw new Error("Invalid symbol for InputSignal set method");
|
|
46
|
-
}
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region ../packages/core/src/signals/input/input.ts
|
|
49
|
-
/**
|
|
50
|
-
* Creates an `InputSignal` — a specialized reactive state designed for use
|
|
51
|
-
* as a property signal in web components.
|
|
52
|
-
*
|
|
53
|
-
* Unlike a plain `Signal.State`, the `set` method of an `InputSignal` is
|
|
54
|
-
* restricted to internal callers (identified by the private symbol) and
|
|
55
|
-
* accepts an optional `transform` function that converts incoming values
|
|
56
|
-
* (e.g. raw HTML attribute strings) into the internally stored type before
|
|
57
|
-
* updating the signal.
|
|
58
|
-
*
|
|
59
|
-
* @param value - The initial value of the signal.
|
|
60
|
-
* @param options - Optional configuration including an equality function,
|
|
61
|
-
* lifecycle hooks, and a `transform` function applied to incoming values.
|
|
62
|
-
* @returns A new `InputSignal` instance.
|
|
63
|
-
*/
|
|
64
|
-
function input(value, options) {
|
|
65
|
-
const transform = options?.transform;
|
|
66
|
-
delete options?.transform;
|
|
67
|
-
const signal = new Signal.State(value, options);
|
|
68
|
-
const originalSet = signal.set;
|
|
69
|
-
const getter = function() {
|
|
70
|
-
return signal.get();
|
|
71
|
-
};
|
|
72
|
-
Object.assign(getter, {
|
|
73
|
-
set(newValue, symbol) {
|
|
74
|
-
assertPrivateContext(symbol);
|
|
75
|
-
const transformedValue = transform ? transform(newValue) : newValue;
|
|
76
|
-
originalSet.call(signal, transformedValue);
|
|
77
|
-
},
|
|
78
|
-
get: signal.get.bind(signal)
|
|
79
|
-
});
|
|
80
|
-
getter[INPUT_SIGNAL_INSTANCE_SYMBOL] = true;
|
|
81
|
-
return getter;
|
|
82
|
-
}
|
|
83
|
-
//#endregion
|
|
84
|
-
//#region ../packages/core/src/signals/computed/computed.ts
|
|
85
|
-
/**
|
|
86
|
-
* Creates a read-only computed signal whose value is derived from other signals.
|
|
87
|
-
*
|
|
88
|
-
* Returns a callable getter that reads the current value, augmented with the
|
|
89
|
-
* underlying {@link Signal.State} API.
|
|
90
|
-
*
|
|
91
|
-
* @template Value - The type of the computed value. Defaults to `any`.
|
|
92
|
-
* @param value - The initial (seed) value of the computed signal.
|
|
93
|
-
* @param options - Configuration options for the underlying signal.
|
|
94
|
-
* @returns A {@link Computed} instance.
|
|
95
|
-
*/
|
|
96
|
-
function computed(value, options) {
|
|
97
|
-
const signal = new Signal.State(value, options);
|
|
98
|
-
const getter = function() {
|
|
99
|
-
return signal.get();
|
|
100
|
-
};
|
|
101
|
-
Object.assign(getter, { get: signal.get.bind(signal) });
|
|
102
|
-
return getter;
|
|
103
|
-
}
|
|
104
|
-
//#endregion
|
|
105
|
-
//#region ../packages/core/src/signals/effect/effect.ts
|
|
106
|
-
/**
|
|
107
|
-
* Runs a side-effectful function and automatically re-runs it whenever any
|
|
108
|
-
* Signal read during its execution changes.
|
|
109
|
-
*
|
|
110
|
-
* Internally, `effect` wraps the user callback inside a `Computed` node
|
|
111
|
-
* (for dependency tracking) and observes it with a `Watcher` (for push
|
|
112
|
-
* notifications). When any tracked dependency changes, the `Watcher`
|
|
113
|
-
* schedules a microtask that re-evaluates the `Computed`, which in turn
|
|
114
|
-
* re-runs the user callback and re-registers the new set of dependencies.
|
|
115
|
-
*
|
|
116
|
-
* The returned disposer function stops the effect: it unwatches the internal
|
|
117
|
-
* `Computed` from the `Watcher`, severing all dependency subscriptions so
|
|
118
|
-
* the callback is never called again and the graph nodes can be
|
|
119
|
-
* garbage-collected.
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```ts
|
|
123
|
-
* const count = new State(0);
|
|
124
|
-
*
|
|
125
|
-
* const stop = effect(() => {
|
|
126
|
-
* console.log('count is', count.get());
|
|
127
|
-
* });
|
|
128
|
-
* // logs: "count is 0"
|
|
129
|
-
*
|
|
130
|
-
* count.set(1); // logs: "count is 1"
|
|
131
|
-
* count.set(2); // logs: "count is 2"
|
|
132
|
-
*
|
|
133
|
-
* stop(); // no more logs
|
|
134
|
-
* count.set(3); // silent
|
|
135
|
-
* ```
|
|
136
|
-
*
|
|
137
|
-
* @param fn - The side-effectful function to run. Any Signal read inside it
|
|
138
|
-
* is tracked as a dependency.
|
|
139
|
-
* @returns A disposer function that, when called, permanently stops the effect.
|
|
140
|
-
*/
|
|
141
|
-
function effect(fn, options) {
|
|
142
|
-
/**
|
|
143
|
-
* Wrap the user callback in a Computed so that automatic dependency
|
|
144
|
-
* tracking (via pushComputed / popComputed) works for free.
|
|
145
|
-
* The Computed always returns `undefined` — we only care about the
|
|
146
|
-
* side-effects and the tracked sources, not the value.
|
|
147
|
-
*/
|
|
148
|
-
const computed = new Signal.Computed(() => fn());
|
|
149
|
-
let needsEnqueue = true;
|
|
150
|
-
/**
|
|
151
|
-
* The Watcher is notified synchronously as soon as any tracked dependency
|
|
152
|
-
* changes. Its job is purely to schedule the re-execution; the actual
|
|
153
|
-
* re-evaluation happens asynchronously in a microtask so that multiple
|
|
154
|
-
* synchronous signal updates are batched into a single re-run.
|
|
155
|
-
*/
|
|
156
|
-
const watcher = new Signal.subtle.Watcher(() => {
|
|
157
|
-
if (needsEnqueue) {
|
|
158
|
-
needsEnqueue = false;
|
|
159
|
-
queueMicrotask(() => {
|
|
160
|
-
needsEnqueue = true;
|
|
161
|
-
options?.onBeforeRun?.();
|
|
162
|
-
const pendings = watcher.getPending();
|
|
163
|
-
for (let i = 0; i < pendings.length; i++) pendings[i].get();
|
|
164
|
-
options?.onAfterRun?.();
|
|
165
|
-
watcher.watch();
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
options?.onBeforeRun?.();
|
|
170
|
-
watcher.watch(computed);
|
|
171
|
-
computed.get();
|
|
172
|
-
options?.onAfterRun?.();
|
|
173
|
-
/**
|
|
174
|
-
* Disposer — call this to permanently stop the effect.
|
|
175
|
-
*
|
|
176
|
-
* Unwatching the Computed tears down the entire live dependency chain
|
|
177
|
-
* (Watcher → Computed → all sources), preventing any further
|
|
178
|
-
* notifications and allowing GC.
|
|
179
|
-
*/
|
|
180
|
-
return () => {
|
|
181
|
-
options?.onCleanup?.();
|
|
182
|
-
watcher.unwatch(computed);
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
//#endregion
|
|
186
|
-
//#region ../packages/core/src/signals/signal/signal.ts
|
|
187
|
-
/**
|
|
188
|
-
* Creates a writable reactive signal.
|
|
189
|
-
*
|
|
190
|
-
* Returns a callable getter that reads the current value, augmented with the
|
|
191
|
-
* underlying {@link Signal.State} API and an `update` method to derive the next
|
|
192
|
-
* value from the previous one.
|
|
193
|
-
*
|
|
194
|
-
* @template T - The type of the stored value. Defaults to `any`.
|
|
195
|
-
* @param value - The initial value of the signal.
|
|
196
|
-
* @param options - Configuration options for the signal.
|
|
197
|
-
* @returns A {@link SignalType} instance.
|
|
198
|
-
*/
|
|
199
|
-
function signal(value, options) {
|
|
200
|
-
const signal = new Signal.State(value, options);
|
|
201
|
-
const getter = function() {
|
|
202
|
-
return signal.get();
|
|
203
|
-
};
|
|
204
|
-
Object.assign(getter, {
|
|
205
|
-
set: signal.set.bind(signal),
|
|
206
|
-
get: signal.get.bind(signal),
|
|
207
|
-
update: (updater) => signal.set(updater(signal.get()))
|
|
208
|
-
});
|
|
209
|
-
return getter;
|
|
210
|
-
}
|
|
211
|
-
//#endregion
|
|
212
|
-
//#region ../packages/core/src/signals/untracked.ts
|
|
213
|
-
/**
|
|
214
|
-
* Executes a function without tracking any dependencies.
|
|
215
|
-
* @param fn - The function to execute without tracking.
|
|
216
|
-
* @returns The result of the function execution.
|
|
217
|
-
*/
|
|
218
|
-
var untracked = Signal.subtle.untrack;
|
|
219
|
-
//#endregion
|
|
220
|
-
Object.defineProperty(exports, "INPUT_SIGNAL_SET_SYMBOL", {
|
|
221
|
-
enumerable: true,
|
|
222
|
-
get: function() {
|
|
223
|
-
return INPUT_SIGNAL_SET_SYMBOL;
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
Object.defineProperty(exports, "computed", {
|
|
227
|
-
enumerable: true,
|
|
228
|
-
get: function() {
|
|
229
|
-
return computed;
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
Object.defineProperty(exports, "effect", {
|
|
233
|
-
enumerable: true,
|
|
234
|
-
get: function() {
|
|
235
|
-
return effect;
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
Object.defineProperty(exports, "input", {
|
|
239
|
-
enumerable: true,
|
|
240
|
-
get: function() {
|
|
241
|
-
return input;
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
Object.defineProperty(exports, "isInputSignal", {
|
|
245
|
-
enumerable: true,
|
|
246
|
-
get: function() {
|
|
247
|
-
return isInputSignal;
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
Object.defineProperty(exports, "signal", {
|
|
251
|
-
enumerable: true,
|
|
252
|
-
get: function() {
|
|
253
|
-
return signal;
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
Object.defineProperty(exports, "untracked", {
|
|
257
|
-
enumerable: true,
|
|
258
|
-
get: function() {
|
|
259
|
-
return untracked;
|
|
260
|
-
}
|
|
261
|
-
});
|