@vaadin/hilla-react-signals 24.7.0-alpha9 → 24.7.0-beta3
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/CollectionSignal.d.ts +0 -9
- package/CollectionSignal.js +9 -15
- package/CollectionSignal.js.map +1 -7
- package/FullStackSignal.d.ts +0 -88
- package/FullStackSignal.js +151 -195
- package/FullStackSignal.js.map +1 -7
- package/ListSignal.d.ts +0 -22
- package/ListSignal.js +112 -138
- package/ListSignal.js.map +1 -7
- package/NumberSignal.d.ts +0 -37
- package/NumberSignal.js +29 -49
- package/NumberSignal.js.map +1 -7
- package/ValueSignal.d.ts +0 -40
- package/ValueSignal.js +58 -105
- package/ValueSignal.js.map +1 -7
- package/core.d.ts +0 -1
- package/core.js +2 -2
- package/core.js.map +1 -7
- package/events.d.ts +0 -11
- package/events.js +72 -71
- package/events.js.map +1 -7
- package/index.d.ts +0 -1
- package/index.js +7 -13
- package/index.js.map +1 -7
- package/package.json +9 -34
- package/polyfills.d.ts +0 -1
- package/polyfills.js +15 -14
- package/polyfills.js.map +1 -7
- package/types.d.ts +4 -7
- package/types.js +2 -0
- package/types.js.map +1 -0
- package/utils.d.ts +0 -1
- package/utils.js +10 -13
- package/utils.js.map +1 -7
- package/CollectionSignal.d.ts.map +0 -1
- package/FullStackSignal.d.ts.map +0 -1
- package/ListSignal.d.ts.map +0 -1
- package/NumberSignal.d.ts.map +0 -1
- package/ValueSignal.d.ts.map +0 -1
- package/core.d.ts.map +0 -1
- package/events.d.ts.map +0 -1
- package/index.d.ts.map +0 -1
- package/polyfills.d.ts.map +0 -1
- package/utils.d.ts.map +0 -1
package/ValueSignal.js
CHANGED
|
@@ -1,109 +1,62 @@
|
|
|
1
|
-
import { nanoid } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
$setValueQuietly,
|
|
14
|
-
$update,
|
|
15
|
-
FullStackSignal
|
|
16
|
-
} from "./FullStackSignal.js";
|
|
17
|
-
class ValueSignal extends FullStackSignal {
|
|
18
|
-
#pendingRequests = /* @__PURE__ */ new Map();
|
|
19
|
-
/**
|
|
20
|
-
* Sets the value.
|
|
21
|
-
* Note that the value change event that is propagated to the server as the
|
|
22
|
-
* result of this operation is not taking the last seen value into account and
|
|
23
|
-
* will overwrite the shared value on the server unconditionally (AKA: "Last
|
|
24
|
-
* Write Wins"). If you need to perform a conditional update, use the
|
|
25
|
-
* `replace` method instead.
|
|
26
|
-
*
|
|
27
|
-
* @param value - The new value.
|
|
28
|
-
* @returns An operation object that allows to perform additional actions.
|
|
29
|
-
*/
|
|
30
|
-
set(value) {
|
|
31
|
-
const { parentClientSignalId } = this.server.config;
|
|
32
|
-
const signalId = parentClientSignalId !== void 0 ? this.id : void 0;
|
|
33
|
-
const event = createSetStateEvent(value, signalId, parentClientSignalId);
|
|
34
|
-
const promise = this[$update](event);
|
|
35
|
-
this[$setValueQuietly](value);
|
|
36
|
-
return this[$createOperation]({ id: event.id, promise });
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Replaces the value with a new one only if the current value is equal to the
|
|
40
|
-
* expected value.
|
|
41
|
-
*
|
|
42
|
-
* @param expected - The expected value.
|
|
43
|
-
* @param newValue - The new value.
|
|
44
|
-
* @returns An operation object that allows to perform additional actions.
|
|
45
|
-
*/
|
|
46
|
-
replace(expected, newValue) {
|
|
47
|
-
const { parentClientSignalId } = this.server.config;
|
|
48
|
-
const signalId = parentClientSignalId !== void 0 ? this.id : void 0;
|
|
49
|
-
const event = createReplaceStateEvent(expected, newValue, signalId, parentClientSignalId);
|
|
50
|
-
const promise = this[$update](event);
|
|
51
|
-
return this[$createOperation]({ id: event.id, promise });
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Tries to update the value by applying the callback function to the current
|
|
55
|
-
* value. In case of a concurrent change, the callback is run again with an
|
|
56
|
-
* updated input value. This is repeated until the result can be applied
|
|
57
|
-
* without concurrent changes, or the operation is canceled.
|
|
58
|
-
*
|
|
59
|
-
* Note that there is no guarantee that cancel() will be effective always,
|
|
60
|
-
* since a succeeding operation might already be on its way to the server.
|
|
61
|
-
*
|
|
62
|
-
* @param callback - The function that is applied on the current value to
|
|
63
|
-
* produce the new value.
|
|
64
|
-
* @returns An operation object that allows to perform additional actions,
|
|
65
|
-
* including cancellation.
|
|
66
|
-
*/
|
|
67
|
-
update(callback) {
|
|
68
|
-
const newValue = callback(this.value);
|
|
69
|
-
const event = createReplaceStateEvent(this.value, newValue);
|
|
70
|
-
const promise = this[$update](event);
|
|
71
|
-
const pendingRequest = { id: nanoid(), callback, canceled: false };
|
|
72
|
-
this.#pendingRequests.set(event.id, pendingRequest);
|
|
73
|
-
return {
|
|
74
|
-
...this[$createOperation]({ id: pendingRequest.id, promise }),
|
|
75
|
-
cancel: () => {
|
|
76
|
-
pendingRequest.canceled = true;
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
[$processServerResponse](event) {
|
|
81
|
-
const record = this.#pendingRequests.get(event.id);
|
|
82
|
-
if (record) {
|
|
83
|
-
this.#pendingRequests.delete(event.id);
|
|
84
|
-
if (!(event.accepted || record.canceled)) {
|
|
85
|
-
this.update(record.callback);
|
|
86
|
-
}
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
import { createReplaceStateEvent, createSetStateEvent, isReplaceStateEvent, isSetStateEvent, isSnapshotStateEvent, } from './events.js';
|
|
3
|
+
import { $createOperation, $processServerResponse, $resolveOperation, $setValueQuietly, $update, FullStackSignal, } from './FullStackSignal.js';
|
|
4
|
+
export class ValueSignal extends FullStackSignal {
|
|
5
|
+
#pendingRequests = new Map();
|
|
6
|
+
set(value) {
|
|
7
|
+
const { parentClientSignalId } = this.server.config;
|
|
8
|
+
const signalId = parentClientSignalId !== undefined ? this.id : undefined;
|
|
9
|
+
const event = createSetStateEvent(value, signalId, parentClientSignalId);
|
|
10
|
+
const promise = this[$update](event);
|
|
11
|
+
this[$setValueQuietly](value);
|
|
12
|
+
return this[$createOperation]({ id: event.id, promise });
|
|
87
13
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
14
|
+
replace(expected, newValue) {
|
|
15
|
+
const { parentClientSignalId } = this.server.config;
|
|
16
|
+
const signalId = parentClientSignalId !== undefined ? this.id : undefined;
|
|
17
|
+
const event = createReplaceStateEvent(expected, newValue, signalId, parentClientSignalId);
|
|
18
|
+
const promise = this[$update](event);
|
|
19
|
+
return this[$createOperation]({ id: event.id, promise });
|
|
93
20
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
21
|
+
update(callback) {
|
|
22
|
+
const newValue = callback(this.value);
|
|
23
|
+
const event = createReplaceStateEvent(this.value, newValue);
|
|
24
|
+
const promise = this[$update](event);
|
|
25
|
+
const pendingRequest = { id: nanoid(), callback, canceled: false };
|
|
26
|
+
this.#pendingRequests.set(event.id, pendingRequest);
|
|
27
|
+
return {
|
|
28
|
+
...this[$createOperation]({ id: pendingRequest.id, promise }),
|
|
29
|
+
cancel: () => {
|
|
30
|
+
pendingRequest.canceled = true;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
[$processServerResponse](event) {
|
|
35
|
+
const record = this.#pendingRequests.get(event.id);
|
|
36
|
+
if (record) {
|
|
37
|
+
this.#pendingRequests.delete(event.id);
|
|
38
|
+
if (!(event.accepted || record.canceled)) {
|
|
39
|
+
this.update(record.callback);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let reason;
|
|
43
|
+
if (event.accepted || isSnapshotStateEvent(event)) {
|
|
44
|
+
this.#applyAcceptedEvent(event);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
reason = `Server rejected the operation with id '${event.id}'. See the server log for more details.`;
|
|
48
|
+
}
|
|
49
|
+
[record?.id, event.id].filter(Boolean).forEach((id) => this[$resolveOperation](id, reason));
|
|
50
|
+
}
|
|
51
|
+
#applyAcceptedEvent(event) {
|
|
52
|
+
if (isSetStateEvent(event) || isSnapshotStateEvent(event)) {
|
|
53
|
+
this.value = event.value;
|
|
54
|
+
}
|
|
55
|
+
else if (isReplaceStateEvent(event)) {
|
|
56
|
+
if (JSON.stringify(this.value) === JSON.stringify(event.expected)) {
|
|
57
|
+
this.value = event.value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
103
60
|
}
|
|
104
|
-
}
|
|
105
61
|
}
|
|
106
|
-
|
|
107
|
-
ValueSignal
|
|
108
|
-
};
|
|
109
|
-
//# sourceMappingURL=ValueSignal.js.map
|
|
62
|
+
//# sourceMappingURL=ValueSignal.js.map
|
package/ValueSignal.js.map
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["src/ValueSignal.ts"],
|
|
4
|
-
"sourcesContent": ["import { nanoid } from 'nanoid';\nimport {\n createReplaceStateEvent,\n createSetStateEvent,\n isReplaceStateEvent,\n isSetStateEvent,\n isSnapshotStateEvent,\n type StateEvent,\n} from './events.js';\nimport {\n $createOperation,\n $processServerResponse,\n $resolveOperation,\n $setValueQuietly,\n $update,\n FullStackSignal,\n type Operation,\n} from './FullStackSignal.js';\n\ntype PendingRequestsRecord<T> = Readonly<{\n id: string;\n callback(value: T): T;\n}> & { canceled: boolean };\n\n/**\n * An operation subscription that can be canceled.\n */\nexport interface OperationSubscription extends Operation {\n cancel(): void;\n}\n\n/**\n * A full-stack signal that holds an arbitrary value.\n */\nexport class ValueSignal<T> extends FullStackSignal<T> {\n readonly #pendingRequests = new Map<string, PendingRequestsRecord<T>>();\n\n /**\n * Sets the value.\n * Note that the value change event that is propagated to the server as the\n * result of this operation is not taking the last seen value into account and\n * will overwrite the shared value on the server unconditionally (AKA: \"Last\n * Write Wins\"). If you need to perform a conditional update, use the\n * `replace` method instead.\n *\n * @param value - The new value.\n * @returns An operation object that allows to perform additional actions.\n */\n set(value: T): Operation {\n const { parentClientSignalId } = this.server.config;\n const signalId = parentClientSignalId !== undefined ? this.id : undefined;\n const event = createSetStateEvent(value, signalId, parentClientSignalId);\n const promise = this[$update](event);\n this[$setValueQuietly](value);\n return this[$createOperation]({ id: event.id, promise });\n }\n\n /**\n * Replaces the value with a new one only if the current value is equal to the\n * expected value.\n *\n * @param expected - The expected value.\n * @param newValue - The new value.\n * @returns An operation object that allows to perform additional actions.\n */\n replace(expected: T, newValue: T): Operation {\n const { parentClientSignalId } = this.server.config;\n const signalId = parentClientSignalId !== undefined ? this.id : undefined;\n const event = createReplaceStateEvent(expected, newValue, signalId, parentClientSignalId);\n const promise = this[$update](event);\n return this[$createOperation]({ id: event.id, promise });\n }\n\n /**\n * Tries to update the value by applying the callback function to the current\n * value. In case of a concurrent change, the callback is run again with an\n * updated input value. This is repeated until the result can be applied\n * without concurrent changes, or the operation is canceled.\n *\n * Note that there is no guarantee that cancel() will be effective always,\n * since a succeeding operation might already be on its way to the server.\n *\n * @param callback - The function that is applied on the current value to\n * produce the new value.\n * @returns An operation object that allows to perform additional actions,\n * including cancellation.\n */\n update(callback: (value: T) => T): OperationSubscription {\n const newValue = callback(this.value);\n const event = createReplaceStateEvent(this.value, newValue);\n const promise = this[$update](event);\n const pendingRequest = { id: nanoid(), callback, canceled: false };\n this.#pendingRequests.set(event.id, pendingRequest);\n return {\n ...this[$createOperation]({ id: pendingRequest.id, promise }),\n cancel: () => {\n pendingRequest.canceled = true;\n },\n };\n }\n\n protected override [$processServerResponse](event: StateEvent): void {\n const record = this.#pendingRequests.get(event.id);\n if (record) {\n this.#pendingRequests.delete(event.id);\n\n if (!(event.accepted || record.canceled)) {\n this.update(record.callback);\n }\n }\n\n let reason: string | undefined;\n if (event.accepted || isSnapshotStateEvent<T>(event)) {\n this.#applyAcceptedEvent(event);\n } else {\n reason = `Server rejected the operation with id '${event.id}'. See the server log for more details.`;\n }\n // `then` callbacks can be associated to the record or the event\n // it depends on the operation that was performed\n [record?.id, event.id].filter(Boolean).forEach((id) => this[$resolveOperation](id!, reason));\n }\n\n #applyAcceptedEvent(event: StateEvent): void {\n if (isSetStateEvent<T>(event) || isSnapshotStateEvent<T>(event)) {\n this.value = event.value;\n } else if (isReplaceStateEvent<T>(event)) {\n if (JSON.stringify(this.value) === JSON.stringify(event.expected)) {\n this.value = event.value;\n }\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAiBA,MAAM,oBAAuB,gBAAmB;AAAA,EAC5C,mBAAmB,oBAAI,IAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAatE,IAAI,OAAqB;AACvB,UAAM,EAAE,qBAAqB,IAAI,KAAK,OAAO;AAC7C,UAAM,WAAW,yBAAyB,SAAY,KAAK,KAAK;AAChE,UAAM,QAAQ,oBAAoB,OAAO,UAAU,oBAAoB;AACvE,UAAM,UAAU,KAAK,OAAO,EAAE,KAAK;AACnC,SAAK,gBAAgB,EAAE,KAAK;AAC5B,WAAO,KAAK,gBAAgB,EAAE,EAAE,IAAI,MAAM,IAAI,QAAQ,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,QAAQ,UAAa,UAAwB;AAC3C,UAAM,EAAE,qBAAqB,IAAI,KAAK,OAAO;AAC7C,UAAM,WAAW,yBAAyB,SAAY,KAAK,KAAK;AAChE,UAAM,QAAQ,wBAAwB,UAAU,UAAU,UAAU,oBAAoB;AACxF,UAAM,UAAU,KAAK,OAAO,EAAE,KAAK;AACnC,WAAO,KAAK,gBAAgB,EAAE,EAAE,IAAI,MAAM,IAAI,QAAQ,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,OAAO,UAAkD;AACvD,UAAM,WAAW,SAAS,KAAK,KAAK;AACpC,UAAM,QAAQ,wBAAwB,KAAK,OAAO,QAAQ;AAC1D,UAAM,UAAU,KAAK,OAAO,EAAE,KAAK;AACnC,UAAM,iBAAiB,EAAE,IAAI,OAAO,GAAG,UAAU,UAAU,MAAM;AACjE,SAAK,iBAAiB,IAAI,MAAM,IAAI,cAAc;AAClD,WAAO;AAAA,MACL,GAAG,KAAK,gBAAgB,EAAE,EAAE,IAAI,eAAe,IAAI,QAAQ,CAAC;AAAA,MAC5D,QAAQ,MAAM;AACZ,uBAAe,WAAW;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,CAAoB,sBAAsB,EAAE,OAAyB;AACnE,UAAM,SAAS,KAAK,iBAAiB,IAAI,MAAM,EAAE;AACjD,QAAI,QAAQ;AACV,WAAK,iBAAiB,OAAO,MAAM,EAAE;AAErC,UAAI,EAAE,MAAM,YAAY,OAAO,WAAW;AACxC,aAAK,OAAO,OAAO,QAAQ;AAAA,MAC7B;AAAA,IACF;AAEA,QAAI;AACJ,QAAI,MAAM,YAAY,qBAAwB,KAAK,GAAG;AACpD,WAAK,oBAAoB,KAAK;AAAA,IAChC,OAAO;AACL,eAAS,0CAA0C,MAAM,EAAE;AAAA,IAC7D;AAGA,KAAC,QAAQ,IAAI,MAAM,EAAE,EAAE,OAAO,OAAO,EAAE,QAAQ,CAAC,OAAO,KAAK,iBAAiB,EAAE,IAAK,MAAM,CAAC;AAAA,EAC7F;AAAA,EAEA,oBAAoB,OAAyB;AAC3C,QAAI,gBAAmB,KAAK,KAAK,qBAAwB,KAAK,GAAG;AAC/D,WAAK,QAAQ,MAAM;AAAA,IACrB,WAAW,oBAAuB,KAAK,GAAG;AACxC,UAAI,KAAK,UAAU,KAAK,KAAK,MAAM,KAAK,UAAU,MAAM,QAAQ,GAAG;AACjE,aAAK,QAAQ,MAAM;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
1
|
+
{"version":3,"file":"ValueSignal.js","sourceRoot":"","sources":["src/ValueSignal.ts"],"names":[],"mappings":"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","sourcesContent":["import { nanoid } from 'nanoid';\nimport {\n createReplaceStateEvent,\n createSetStateEvent,\n isReplaceStateEvent,\n isSetStateEvent,\n isSnapshotStateEvent,\n type StateEvent,\n} from './events.js';\nimport {\n $createOperation,\n $processServerResponse,\n $resolveOperation,\n $setValueQuietly,\n $update,\n FullStackSignal,\n type Operation,\n} from './FullStackSignal.js';\n\ntype PendingRequestsRecord<T> = Readonly<{\n id: string;\n callback(value: T): T;\n}> & { canceled: boolean };\n\n/**\n * An operation subscription that can be canceled.\n */\nexport interface OperationSubscription extends Operation {\n cancel(): void;\n}\n\n/**\n * A full-stack signal that holds an arbitrary value.\n */\nexport class ValueSignal<T> extends FullStackSignal<T> {\n readonly #pendingRequests = new Map<string, PendingRequestsRecord<T>>();\n\n /**\n * Sets the value.\n * Note that the value change event that is propagated to the server as the\n * result of this operation is not taking the last seen value into account and\n * will overwrite the shared value on the server unconditionally (AKA: \"Last\n * Write Wins\"). If you need to perform a conditional update, use the\n * `replace` method instead.\n *\n * @param value - The new value.\n * @returns An operation object that allows to perform additional actions.\n */\n set(value: T): Operation {\n const { parentClientSignalId } = this.server.config;\n const signalId = parentClientSignalId !== undefined ? this.id : undefined;\n const event = createSetStateEvent(value, signalId, parentClientSignalId);\n const promise = this[$update](event);\n this[$setValueQuietly](value);\n return this[$createOperation]({ id: event.id, promise });\n }\n\n /**\n * Replaces the value with a new one only if the current value is equal to the\n * expected value.\n *\n * @param expected - The expected value.\n * @param newValue - The new value.\n * @returns An operation object that allows to perform additional actions.\n */\n replace(expected: T, newValue: T): Operation {\n const { parentClientSignalId } = this.server.config;\n const signalId = parentClientSignalId !== undefined ? this.id : undefined;\n const event = createReplaceStateEvent(expected, newValue, signalId, parentClientSignalId);\n const promise = this[$update](event);\n return this[$createOperation]({ id: event.id, promise });\n }\n\n /**\n * Tries to update the value by applying the callback function to the current\n * value. In case of a concurrent change, the callback is run again with an\n * updated input value. This is repeated until the result can be applied\n * without concurrent changes, or the operation is canceled.\n *\n * Note that there is no guarantee that cancel() will be effective always,\n * since a succeeding operation might already be on its way to the server.\n *\n * @param callback - The function that is applied on the current value to\n * produce the new value.\n * @returns An operation object that allows to perform additional actions,\n * including cancellation.\n */\n update(callback: (value: T) => T): OperationSubscription {\n const newValue = callback(this.value);\n const event = createReplaceStateEvent(this.value, newValue);\n const promise = this[$update](event);\n const pendingRequest = { id: nanoid(), callback, canceled: false };\n this.#pendingRequests.set(event.id, pendingRequest);\n return {\n ...this[$createOperation]({ id: pendingRequest.id, promise }),\n cancel: () => {\n pendingRequest.canceled = true;\n },\n };\n }\n\n protected override [$processServerResponse](event: StateEvent): void {\n const record = this.#pendingRequests.get(event.id);\n if (record) {\n this.#pendingRequests.delete(event.id);\n\n if (!(event.accepted || record.canceled)) {\n this.update(record.callback);\n }\n }\n\n let reason: string | undefined;\n if (event.accepted || isSnapshotStateEvent<T>(event)) {\n this.#applyAcceptedEvent(event);\n } else {\n reason = `Server rejected the operation with id '${event.id}'. See the server log for more details.`;\n }\n // `then` callbacks can be associated to the record or the event\n // it depends on the operation that was performed\n [record?.id, event.id].filter(Boolean).forEach((id) => this[$resolveOperation](id!, reason));\n }\n\n #applyAcceptedEvent(event: StateEvent): void {\n if (isSetStateEvent<T>(event) || isSnapshotStateEvent<T>(event)) {\n this.value = event.value;\n } else if (isReplaceStateEvent<T>(event)) {\n if (JSON.stringify(this.value) === JSON.stringify(event.expected)) {\n this.value = event.value;\n }\n }\n }\n}\n"]}
|
package/core.d.ts
CHANGED
package/core.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
//# sourceMappingURL=core.js.map
|
|
1
|
+
export * from '@preact/signals-react';
|
|
2
|
+
//# sourceMappingURL=core.js.map
|
package/core.js.map
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["src/core.ts"],
|
|
4
|
-
"sourcesContent": ["export * from '@preact/signals-react';\n"],
|
|
5
|
-
"mappings": "AAAA,cAAc;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["src/core.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC","sourcesContent":["export * from '@preact/signals-react';\n"]}
|
package/events.d.ts
CHANGED
|
@@ -5,21 +5,11 @@ export type StateEvent = Readonly<{
|
|
|
5
5
|
accepted: boolean;
|
|
6
6
|
parentSignalId?: string;
|
|
7
7
|
}>;
|
|
8
|
-
/**
|
|
9
|
-
* Creates a new state event type.
|
|
10
|
-
*/
|
|
11
8
|
type CreateStateEventType<V, T extends string, C extends Record<string, unknown> = Record<never, never>> = Readonly<{
|
|
12
9
|
type: T;
|
|
13
10
|
value: V;
|
|
14
11
|
}> & Readonly<C> & StateEvent;
|
|
15
|
-
/**
|
|
16
|
-
* A state event received from the server describing the current state of the
|
|
17
|
-
* signal.
|
|
18
|
-
*/
|
|
19
12
|
export type SnapshotStateEvent<T> = CreateStateEventType<T, 'snapshot'>;
|
|
20
|
-
/**
|
|
21
|
-
* A state event defines a new value of the signal shared with the server. The
|
|
22
|
-
*/
|
|
23
13
|
export type SetStateEvent<T> = CreateStateEventType<T, 'set'>;
|
|
24
14
|
export declare function createSetStateEvent<T>(value: T, signalId?: string, parentSignalId?: string): SetStateEvent<T>;
|
|
25
15
|
export type ReplaceStateEvent<T> = CreateStateEventType<T, 'replace', {
|
|
@@ -54,4 +44,3 @@ export declare function isListSnapshotStateEvent<T>(event: unknown): event is Li
|
|
|
54
44
|
export declare function isInsertLastStateEvent<T>(event: unknown): event is InsertLastStateEvent<T>;
|
|
55
45
|
export declare function isRemoveStateEvent(event: unknown): event is RemoveStateEvent;
|
|
56
46
|
export {};
|
|
57
|
-
//# sourceMappingURL=events.d.ts.map
|
package/events.js
CHANGED
|
@@ -1,85 +1,86 @@
|
|
|
1
|
-
import { nanoid } from
|
|
2
|
-
function createSetStateEvent(value, signalId, parentSignalId) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
export function createSetStateEvent(value, signalId, parentSignalId) {
|
|
3
|
+
return {
|
|
4
|
+
id: signalId ?? nanoid(),
|
|
5
|
+
type: 'set',
|
|
6
|
+
value,
|
|
7
|
+
accepted: false,
|
|
8
|
+
...(parentSignalId !== undefined ? { parentSignalId } : {}),
|
|
9
|
+
};
|
|
10
10
|
}
|
|
11
|
-
function createReplaceStateEvent(expected, value, signalId, parentSignalId) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
export function createReplaceStateEvent(expected, value, signalId, parentSignalId) {
|
|
12
|
+
return {
|
|
13
|
+
id: signalId ?? nanoid(),
|
|
14
|
+
type: 'replace',
|
|
15
|
+
value,
|
|
16
|
+
expected,
|
|
17
|
+
accepted: false,
|
|
18
|
+
...(parentSignalId !== undefined ? { parentSignalId } : {}),
|
|
19
|
+
};
|
|
20
20
|
}
|
|
21
|
-
function createIncrementStateEvent(delta) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
export function createIncrementStateEvent(delta) {
|
|
22
|
+
return {
|
|
23
|
+
id: nanoid(),
|
|
24
|
+
type: 'increment',
|
|
25
|
+
value: delta,
|
|
26
|
+
accepted: false,
|
|
27
|
+
};
|
|
28
28
|
}
|
|
29
|
-
function createInsertLastStateEvent(value) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
export function createInsertLastStateEvent(value) {
|
|
30
|
+
return {
|
|
31
|
+
id: nanoid(),
|
|
32
|
+
type: 'insert',
|
|
33
|
+
value,
|
|
34
|
+
position: 'last',
|
|
35
|
+
accepted: false,
|
|
36
|
+
};
|
|
37
37
|
}
|
|
38
|
-
function createRemoveStateEvent(entryId) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
export function createRemoveStateEvent(entryId) {
|
|
39
|
+
return {
|
|
40
|
+
id: nanoid(),
|
|
41
|
+
type: 'remove',
|
|
42
|
+
entryId,
|
|
43
|
+
value: undefined,
|
|
44
|
+
accepted: false,
|
|
45
|
+
};
|
|
46
46
|
}
|
|
47
47
|
function isStateEvent(event) {
|
|
48
|
-
|
|
48
|
+
return (typeof event === 'object' &&
|
|
49
|
+
event !== null &&
|
|
50
|
+
typeof event.id === 'string' &&
|
|
51
|
+
typeof event.type === 'string' &&
|
|
52
|
+
typeof event.value !== 'undefined' &&
|
|
53
|
+
typeof event.accepted === 'boolean');
|
|
49
54
|
}
|
|
50
|
-
function isSnapshotStateEvent(event) {
|
|
51
|
-
|
|
55
|
+
export function isSnapshotStateEvent(event) {
|
|
56
|
+
return isStateEvent(event) && event.type === 'snapshot';
|
|
52
57
|
}
|
|
53
|
-
function isSetStateEvent(event) {
|
|
54
|
-
|
|
58
|
+
export function isSetStateEvent(event) {
|
|
59
|
+
return isStateEvent(event) && event.type === 'set';
|
|
55
60
|
}
|
|
56
|
-
function isReplaceStateEvent(event) {
|
|
57
|
-
|
|
61
|
+
export function isReplaceStateEvent(event) {
|
|
62
|
+
return (isStateEvent(event) && typeof event.expected !== 'undefined' && event.type === 'replace');
|
|
58
63
|
}
|
|
59
|
-
function isIncrementStateEvent(event) {
|
|
60
|
-
|
|
64
|
+
export function isIncrementStateEvent(event) {
|
|
65
|
+
return isStateEvent(event) && event.type === 'increment';
|
|
61
66
|
}
|
|
62
|
-
function isListSnapshotStateEvent(event) {
|
|
63
|
-
|
|
67
|
+
export function isListSnapshotStateEvent(event) {
|
|
68
|
+
return (typeof event === 'object' &&
|
|
69
|
+
event !== null &&
|
|
70
|
+
typeof event.id === 'string' &&
|
|
71
|
+
event.type === 'snapshot' &&
|
|
72
|
+
event.entries instanceof Array &&
|
|
73
|
+
typeof event.accepted !== 'undefined');
|
|
64
74
|
}
|
|
65
|
-
function isInsertLastStateEvent(event) {
|
|
66
|
-
|
|
75
|
+
export function isInsertLastStateEvent(event) {
|
|
76
|
+
return isStateEvent(event) && event.type === 'insert' && event.position === 'last';
|
|
67
77
|
}
|
|
68
|
-
function isRemoveStateEvent(event) {
|
|
69
|
-
|
|
78
|
+
export function isRemoveStateEvent(event) {
|
|
79
|
+
return (typeof event === 'object' &&
|
|
80
|
+
event !== null &&
|
|
81
|
+
typeof event.id === 'string' &&
|
|
82
|
+
event.type === 'remove' &&
|
|
83
|
+
typeof event.entryId === 'string' &&
|
|
84
|
+
typeof event.value === 'undefined');
|
|
70
85
|
}
|
|
71
|
-
|
|
72
|
-
createIncrementStateEvent,
|
|
73
|
-
createInsertLastStateEvent,
|
|
74
|
-
createRemoveStateEvent,
|
|
75
|
-
createReplaceStateEvent,
|
|
76
|
-
createSetStateEvent,
|
|
77
|
-
isIncrementStateEvent,
|
|
78
|
-
isInsertLastStateEvent,
|
|
79
|
-
isListSnapshotStateEvent,
|
|
80
|
-
isRemoveStateEvent,
|
|
81
|
-
isReplaceStateEvent,
|
|
82
|
-
isSetStateEvent,
|
|
83
|
-
isSnapshotStateEvent
|
|
84
|
-
};
|
|
85
|
-
//# sourceMappingURL=events.js.map
|
|
86
|
+
//# sourceMappingURL=events.js.map
|
package/events.js.map
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["src/events.ts"],
|
|
4
|
-
"sourcesContent": ["import { nanoid } from 'nanoid';\n\nexport type StateEvent = Readonly<{\n id: string;\n type: string;\n value: unknown;\n accepted: boolean;\n parentSignalId?: string;\n}>;\n\n/**\n * Creates a new state event type.\n */\ntype CreateStateEventType<V, T extends string, C extends Record<string, unknown> = Record<never, never>> = Readonly<{\n type: T;\n value: V;\n}> &\n Readonly<C> &\n StateEvent;\n\n/**\n * A state event received from the server describing the current state of the\n * signal.\n */\nexport type SnapshotStateEvent<T> = CreateStateEventType<T, 'snapshot'>;\n\n/**\n * A state event defines a new value of the signal shared with the server. The\n */\nexport type SetStateEvent<T> = CreateStateEventType<T, 'set'>;\n\nexport function createSetStateEvent<T>(value: T, signalId?: string, parentSignalId?: string): SetStateEvent<T> {\n return {\n id: signalId ?? nanoid(),\n type: 'set',\n value,\n accepted: false,\n ...(parentSignalId !== undefined ? { parentSignalId } : {}),\n };\n}\n\nexport type ReplaceStateEvent<T> = CreateStateEventType<T, 'replace', { expected: T }>;\n\nexport function createReplaceStateEvent<T>(\n expected: T,\n value: T,\n signalId?: string,\n parentSignalId?: string,\n): ReplaceStateEvent<T> {\n return {\n id: signalId ?? nanoid(),\n type: 'replace',\n value,\n expected,\n accepted: false,\n ...(parentSignalId !== undefined ? { parentSignalId } : {}),\n };\n}\n\nexport type IncrementStateEvent = CreateStateEventType<number, 'increment'>;\n\nexport function createIncrementStateEvent(delta: number): IncrementStateEvent {\n return {\n id: nanoid(),\n type: 'increment',\n value: delta,\n accepted: false,\n };\n}\n\nexport type ListEntry<T> = Readonly<{\n id: string;\n prev?: string;\n next?: string;\n value: T;\n}>;\n\nexport type ListSnapshotStateEvent<T> = CreateStateEventType<never, 'snapshot', { entries: Array<ListEntry<T>> }>;\n\nexport type InsertLastStateEvent<T> = CreateStateEventType<T, 'insert', { position: 'last'; entryId?: string }>;\n\nexport function createInsertLastStateEvent<T>(value: T): InsertLastStateEvent<T> {\n return {\n id: nanoid(),\n type: 'insert',\n value,\n position: 'last',\n accepted: false,\n };\n}\n\nexport type RemoveStateEvent = CreateStateEventType<never, 'remove', { entryId: string }>;\n\nexport function createRemoveStateEvent(entryId: string): RemoveStateEvent {\n return {\n id: nanoid(),\n type: 'remove',\n entryId,\n value: undefined as never,\n accepted: false,\n };\n}\n\nfunction isStateEvent(event: unknown): event is StateEvent {\n return (\n typeof event === 'object' &&\n event !== null &&\n typeof (event as { id?: unknown }).id === 'string' &&\n typeof (event as { type?: unknown }).type === 'string' &&\n typeof (event as { value?: unknown }).value !== 'undefined' &&\n typeof (event as { accepted?: unknown }).accepted === 'boolean'\n );\n}\n\nexport function isSnapshotStateEvent<T>(event: unknown): event is SnapshotStateEvent<T> {\n return isStateEvent(event) && event.type === 'snapshot';\n}\n\nexport function isSetStateEvent<T>(event: unknown): event is SetStateEvent<T> {\n return isStateEvent(event) && event.type === 'set';\n}\n\nexport function isReplaceStateEvent<T>(event: unknown): event is ReplaceStateEvent<T> {\n return (\n isStateEvent(event) && typeof (event as { expected?: unknown }).expected !== 'undefined' && event.type === 'replace'\n );\n}\n\nexport function isIncrementStateEvent(event: unknown): event is IncrementStateEvent {\n return isStateEvent(event) && event.type === 'increment';\n}\n\nexport function isListSnapshotStateEvent<T>(event: unknown): event is ListSnapshotStateEvent<T> {\n return (\n typeof event === 'object' &&\n event !== null &&\n typeof (event as { id?: unknown }).id === 'string' &&\n (event as { type?: unknown }).type === 'snapshot' &&\n (event as { entries?: unknown }).entries instanceof Array &&\n typeof (event as { accepted?: unknown }).accepted !== 'undefined'\n );\n}\n\nexport function isInsertLastStateEvent<T>(event: unknown): event is InsertLastStateEvent<T> {\n return isStateEvent(event) && event.type === 'insert' && (event as { position?: unknown }).position === 'last';\n}\n\nexport function isRemoveStateEvent(event: unknown): event is RemoveStateEvent {\n return (\n typeof event === 'object' &&\n event !== null &&\n typeof (event as { id?: unknown }).id === 'string' &&\n (event as { type?: unknown }).type === 'remove' &&\n typeof (event as { entryId?: unknown }).entryId === 'string' &&\n typeof (event as { value?: unknown }).value === 'undefined'\n );\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,cAAc;AA+BhB,SAAS,oBAAuB,OAAU,UAAmB,gBAA2C;AAC7G,SAAO;AAAA,IACL,IAAI,YAAY,OAAO;AAAA,IACvB,MAAM;AAAA,IACN;AAAA,IACA,UAAU;AAAA,IACV,GAAI,mBAAmB,SAAY,EAAE,eAAe,IAAI,CAAC;AAAA,EAC3D;AACF;AAIO,SAAS,wBACd,UACA,OACA,UACA,gBACsB;AACtB,SAAO;AAAA,IACL,IAAI,YAAY,OAAO;AAAA,IACvB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,GAAI,mBAAmB,SAAY,EAAE,eAAe,IAAI,CAAC;AAAA,EAC3D;AACF;AAIO,SAAS,0BAA0B,OAAoC;AAC5E,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX,MAAM;AAAA,IACN,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAaO,SAAS,2BAA8B,OAAmC;AAC/E,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX,MAAM;AAAA,IACN;AAAA,IACA,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;AAIO,SAAS,uBAAuB,SAAmC;AACxE,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX,MAAM;AAAA,IACN;AAAA,IACA,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAEA,SAAS,aAAa,OAAqC;AACzD,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA2B,OAAO,YAC1C,OAAQ,MAA6B,SAAS,YAC9C,OAAQ,MAA8B,UAAU,eAChD,OAAQ,MAAiC,aAAa;AAE1D;AAEO,SAAS,qBAAwB,OAAgD;AACtF,SAAO,aAAa,KAAK,KAAK,MAAM,SAAS;AAC/C;AAEO,SAAS,gBAAmB,OAA2C;AAC5E,SAAO,aAAa,KAAK,KAAK,MAAM,SAAS;AAC/C;AAEO,SAAS,oBAAuB,OAA+C;AACpF,SACE,aAAa,KAAK,KAAK,OAAQ,MAAiC,aAAa,eAAe,MAAM,SAAS;AAE/G;AAEO,SAAS,sBAAsB,OAA8C;AAClF,SAAO,aAAa,KAAK,KAAK,MAAM,SAAS;AAC/C;AAEO,SAAS,yBAA4B,OAAoD;AAC9F,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA2B,OAAO,YACzC,MAA6B,SAAS,cACtC,MAAgC,mBAAmB,SACpD,OAAQ,MAAiC,aAAa;AAE1D;AAEO,SAAS,uBAA0B,OAAkD;AAC1F,SAAO,aAAa,KAAK,KAAK,MAAM,SAAS,YAAa,MAAiC,aAAa;AAC1G;AAEO,SAAS,mBAAmB,OAA2C;AAC5E,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA2B,OAAO,YACzC,MAA6B,SAAS,YACvC,OAAQ,MAAgC,YAAY,YACpD,OAAQ,MAA8B,UAAU;AAEpD;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["src/events.ts"],"names":[],"mappings":"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","sourcesContent":["import { nanoid } from 'nanoid';\n\nexport type StateEvent = Readonly<{\n id: string;\n type: string;\n value: unknown;\n accepted: boolean;\n parentSignalId?: string;\n}>;\n\n/**\n * Creates a new state event type.\n */\ntype CreateStateEventType<V, T extends string, C extends Record<string, unknown> = Record<never, never>> = Readonly<{\n type: T;\n value: V;\n}> &\n Readonly<C> &\n StateEvent;\n\n/**\n * A state event received from the server describing the current state of the\n * signal.\n */\nexport type SnapshotStateEvent<T> = CreateStateEventType<T, 'snapshot'>;\n\n/**\n * A state event defines a new value of the signal shared with the server. The\n */\nexport type SetStateEvent<T> = CreateStateEventType<T, 'set'>;\n\nexport function createSetStateEvent<T>(value: T, signalId?: string, parentSignalId?: string): SetStateEvent<T> {\n return {\n id: signalId ?? nanoid(),\n type: 'set',\n value,\n accepted: false,\n ...(parentSignalId !== undefined ? { parentSignalId } : {}),\n };\n}\n\nexport type ReplaceStateEvent<T> = CreateStateEventType<T, 'replace', { expected: T }>;\n\nexport function createReplaceStateEvent<T>(\n expected: T,\n value: T,\n signalId?: string,\n parentSignalId?: string,\n): ReplaceStateEvent<T> {\n return {\n id: signalId ?? nanoid(),\n type: 'replace',\n value,\n expected,\n accepted: false,\n ...(parentSignalId !== undefined ? { parentSignalId } : {}),\n };\n}\n\nexport type IncrementStateEvent = CreateStateEventType<number, 'increment'>;\n\nexport function createIncrementStateEvent(delta: number): IncrementStateEvent {\n return {\n id: nanoid(),\n type: 'increment',\n value: delta,\n accepted: false,\n };\n}\n\nexport type ListEntry<T> = Readonly<{\n id: string;\n prev?: string;\n next?: string;\n value: T;\n}>;\n\nexport type ListSnapshotStateEvent<T> = CreateStateEventType<never, 'snapshot', { entries: Array<ListEntry<T>> }>;\n\nexport type InsertLastStateEvent<T> = CreateStateEventType<T, 'insert', { position: 'last'; entryId?: string }>;\n\nexport function createInsertLastStateEvent<T>(value: T): InsertLastStateEvent<T> {\n return {\n id: nanoid(),\n type: 'insert',\n value,\n position: 'last',\n accepted: false,\n };\n}\n\nexport type RemoveStateEvent = CreateStateEventType<never, 'remove', { entryId: string }>;\n\nexport function createRemoveStateEvent(entryId: string): RemoveStateEvent {\n return {\n id: nanoid(),\n type: 'remove',\n entryId,\n value: undefined as never,\n accepted: false,\n };\n}\n\nfunction isStateEvent(event: unknown): event is StateEvent {\n return (\n typeof event === 'object' &&\n event !== null &&\n typeof (event as { id?: unknown }).id === 'string' &&\n typeof (event as { type?: unknown }).type === 'string' &&\n typeof (event as { value?: unknown }).value !== 'undefined' &&\n typeof (event as { accepted?: unknown }).accepted === 'boolean'\n );\n}\n\nexport function isSnapshotStateEvent<T>(event: unknown): event is SnapshotStateEvent<T> {\n return isStateEvent(event) && event.type === 'snapshot';\n}\n\nexport function isSetStateEvent<T>(event: unknown): event is SetStateEvent<T> {\n return isStateEvent(event) && event.type === 'set';\n}\n\nexport function isReplaceStateEvent<T>(event: unknown): event is ReplaceStateEvent<T> {\n return (\n isStateEvent(event) && typeof (event as { expected?: unknown }).expected !== 'undefined' && event.type === 'replace'\n );\n}\n\nexport function isIncrementStateEvent(event: unknown): event is IncrementStateEvent {\n return isStateEvent(event) && event.type === 'increment';\n}\n\nexport function isListSnapshotStateEvent<T>(event: unknown): event is ListSnapshotStateEvent<T> {\n return (\n typeof event === 'object' &&\n event !== null &&\n typeof (event as { id?: unknown }).id === 'string' &&\n (event as { type?: unknown }).type === 'snapshot' &&\n (event as { entries?: unknown }).entries instanceof Array &&\n typeof (event as { accepted?: unknown }).accepted !== 'undefined'\n );\n}\n\nexport function isInsertLastStateEvent<T>(event: unknown): event is InsertLastStateEvent<T> {\n return isStateEvent(event) && event.type === 'insert' && (event as { position?: unknown }).position === 'last';\n}\n\nexport function isRemoveStateEvent(event: unknown): event is RemoveStateEvent {\n return (\n typeof event === 'object' &&\n event !== null &&\n typeof (event as { id?: unknown }).id === 'string' &&\n (event as { type?: unknown }).type === 'remove' &&\n typeof (event as { entryId?: unknown }).entryId === 'string' &&\n typeof (event as { value?: unknown }).value === 'undefined'\n );\n}\n"]}
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
export * from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
FullStackSignal,
|
|
9
|
-
ListSignal,
|
|
10
|
-
NumberSignal,
|
|
11
|
-
ValueSignal
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import './polyfills.js';
|
|
2
|
+
export * from './core.js';
|
|
3
|
+
export { NumberSignal } from './NumberSignal.js';
|
|
4
|
+
export { ValueSignal } from './ValueSignal.js';
|
|
5
|
+
export { ListSignal } from './ListSignal.js';
|
|
6
|
+
export { FullStackSignal } from './FullStackSignal.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["src/index.ts"],
|
|
4
|
-
"sourcesContent": ["// eslint-disable-next-line import/no-unassigned-import\nimport './polyfills.js';\n\n// eslint-disable-next-line import/export\nexport * from './core.js';\nexport { NumberSignal } from './NumberSignal.js';\nexport { ValueSignal } from './ValueSignal.js';\nexport { ListSignal } from './ListSignal.js';\nexport type { OperationSubscription } from './ValueSignal.js';\nexport { FullStackSignal } from './FullStackSignal.js';\nexport type { Operation } from './FullStackSignal.js';\n"],
|
|
5
|
-
"mappings": "AACA,OAAO;AAGP,cAAc;AACd,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB;AAE3B,SAAS,uBAAuB;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"AACA,OAAO,gBAAgB,CAAC;AAGxB,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["// eslint-disable-next-line import/no-unassigned-import\nimport './polyfills.js';\n\n// eslint-disable-next-line import/export\nexport * from './core.js';\nexport { NumberSignal } from './NumberSignal.js';\nexport { ValueSignal } from './ValueSignal.js';\nexport { ListSignal } from './ListSignal.js';\nexport type { OperationSubscription } from './ValueSignal.js';\nexport { FullStackSignal } from './FullStackSignal.js';\nexport type { Operation } from './FullStackSignal.js';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/hilla-react-signals",
|
|
3
|
-
"version": "24.7.0-
|
|
3
|
+
"version": "24.7.0-beta3",
|
|
4
4
|
"description": "Signals for Hilla React",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.js",
|
|
@@ -17,15 +17,13 @@
|
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
19
|
"clean:build": "git clean -fx . -e .vite -e node_modules",
|
|
20
|
-
"build": "
|
|
21
|
-
"build:esbuild": "tsx ../../../scripts/build.ts",
|
|
22
|
-
"build:dts": "tsc --isolatedModules -p tsconfig.build.json",
|
|
23
|
-
"build:copy": "cd src && copyfiles **/*.d.ts ..",
|
|
20
|
+
"build": "tsx ../../../scripts/build.ts",
|
|
24
21
|
"lint": "eslint src test",
|
|
25
22
|
"lint:fix": "eslint src test --fix",
|
|
26
|
-
"test": "
|
|
27
|
-
"test:coverage": "
|
|
28
|
-
"test:
|
|
23
|
+
"test": "vitest --run",
|
|
24
|
+
"test:coverage": "vitest --run --coverage",
|
|
25
|
+
"test:react": "npm run test",
|
|
26
|
+
"test:watch": "vitest",
|
|
29
27
|
"typecheck": "tsc --noEmit"
|
|
30
28
|
},
|
|
31
29
|
"exports": {
|
|
@@ -46,35 +44,12 @@
|
|
|
46
44
|
"access": "public"
|
|
47
45
|
},
|
|
48
46
|
"dependencies": {
|
|
49
|
-
"@preact/signals-react": "
|
|
50
|
-
"@vaadin/hilla-frontend": "24.7.0-
|
|
51
|
-
"nanoid": "
|
|
47
|
+
"@preact/signals-react": "3.0.1",
|
|
48
|
+
"@vaadin/hilla-frontend": "24.7.0-beta3",
|
|
49
|
+
"nanoid": "5.0.9"
|
|
52
50
|
},
|
|
53
51
|
"peerDependencies": {
|
|
54
52
|
"react": "18 || 19",
|
|
55
53
|
"react-dom": "18 || 19"
|
|
56
|
-
},
|
|
57
|
-
"devDependencies": {
|
|
58
|
-
"@testing-library/dom": "^10.4.0",
|
|
59
|
-
"@testing-library/react": "^16.1.0",
|
|
60
|
-
"@testing-library/user-event": "^14.5.2",
|
|
61
|
-
"@types/chai": "^4.3.20",
|
|
62
|
-
"@types/chai-as-promised": "^7.1.8",
|
|
63
|
-
"@types/chai-dom": "^1.11.3",
|
|
64
|
-
"@types/mocha": "^10.0.10",
|
|
65
|
-
"@types/react": "^18.3.18",
|
|
66
|
-
"@types/react-dom": "^18",
|
|
67
|
-
"@types/sinon": "^10.0.20",
|
|
68
|
-
"@types/sinon-chai": "^3.2.12",
|
|
69
|
-
"@types/validator": "^13.12.2",
|
|
70
|
-
"chai": "^5.1.2",
|
|
71
|
-
"chai-as-promised": "^7.1.2",
|
|
72
|
-
"chai-dom": "^1.12.0",
|
|
73
|
-
"chai-like": "^1.1.3",
|
|
74
|
-
"karma": "^6.4.4",
|
|
75
|
-
"karma-viewport": "^1.0.9",
|
|
76
|
-
"sinon": "^16.1.3",
|
|
77
|
-
"sinon-chai": "^3.7.0",
|
|
78
|
-
"typescript": "5.7.3"
|
|
79
54
|
}
|
|
80
55
|
}
|
package/polyfills.d.ts
CHANGED
package/polyfills.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
if (!(
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
if (!('withResolvers' in Promise)) {
|
|
2
|
+
Object.defineProperty(Promise, 'withResolvers', {
|
|
3
|
+
configurable: true,
|
|
4
|
+
value() {
|
|
5
|
+
let resolve;
|
|
6
|
+
let reject;
|
|
7
|
+
const promise = new Promise((_resolve, _reject) => {
|
|
8
|
+
resolve = _resolve;
|
|
9
|
+
reject = _reject;
|
|
10
|
+
});
|
|
11
|
+
return { resolve: resolve, reject: reject, promise };
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=polyfills.js.map
|
package/polyfills.js.map
CHANGED
|
@@ -1,7 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["src/polyfills.ts"],
|
|
4
|
-
"sourcesContent": ["// TODO: Remove this polyfill when we move to ECMA2024\ndeclare global {\n interface PromiseConstructor {\n withResolvers<T>(): {\n resolve(value: T): void;\n reject(reason?: unknown): void;\n promise: Promise<T>;\n };\n }\n}\n\nif (!('withResolvers' in Promise)) {\n // eslint-disable-next-line no-extend-native\n Object.defineProperty(Promise, 'withResolvers', {\n configurable: true,\n value<T>() {\n let resolve: (value: T) => void;\n let reject: (reason?: unknown) => void;\n const promise = new Promise<T>((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n });\n return { resolve: resolve!, reject: reject!, promise };\n },\n });\n}\n\nexport {};\n"],
|
|
5
|
-
"mappings": "AAWA,IAAI,EAAE,mBAAmB,UAAU;AAEjC,SAAO,eAAe,SAAS,iBAAiB;AAAA,IAC9C,cAAc;AAAA,IACd,QAAW;AACT,UAAI;AACJ,UAAI;AACJ,YAAM,UAAU,IAAI,QAAW,CAAC,UAAU,YAAY;AACpD,kBAAU;AACV,iBAAS;AAAA,MACX,CAAC;AACD,aAAO,EAAE,SAAmB,QAAiB,QAAQ;AAAA,IACvD;AAAA,EACF,CAAC;AACH;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
1
|
+
{"version":3,"file":"polyfills.js","sourceRoot":"","sources":["src/polyfills.ts"],"names":[],"mappings":"AAWA,IAAI,CAAC,CAAC,eAAe,IAAI,OAAO,CAAC,EAAE,CAAC;IAElC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE;QAC9C,YAAY,EAAE,IAAI;QAClB,KAAK;YACH,IAAI,OAA2B,CAAC;YAChC,IAAI,MAAkC,CAAC;YACvC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE;gBACnD,OAAO,GAAG,QAAQ,CAAC;gBACnB,MAAM,GAAG,OAAO,CAAC;YACnB,CAAC,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,EAAE,OAAQ,EAAE,MAAM,EAAE,MAAO,EAAE,OAAO,EAAE,CAAC;QACzD,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,CAAC","sourcesContent":["// TODO: Remove this polyfill when we move to ECMA2024\ndeclare global {\n interface PromiseConstructor {\n withResolvers<T>(): {\n resolve(value: T): void;\n reject(reason?: unknown): void;\n promise: Promise<T>;\n };\n }\n}\n\nif (!('withResolvers' in Promise)) {\n // eslint-disable-next-line no-extend-native\n Object.defineProperty(Promise, 'withResolvers', {\n configurable: true,\n value<T>() {\n let resolve: (value: T) => void;\n let reject: (reason?: unknown) => void;\n const promise = new Promise<T>((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n });\n return { resolve: resolve!, reject: reject!, promise };\n },\n });\n}\n\nexport {};\n"]}
|
package/types.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { Signal as _Signal } from '@preact/signals-react';
|
|
2
|
-
|
|
3
2
|
declare module './core.js' {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
class Signal<T> extends _Signal<T> {
|
|
4
|
+
protected S(node: unknown): void;
|
|
5
|
+
protected U(node: unknown): void;
|
|
6
|
+
}
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
export {};
|
package/types.js
ADDED