@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/ValueSignal.js CHANGED
@@ -1,109 +1,62 @@
1
- import { nanoid } from "nanoid";
2
- import {
3
- createReplaceStateEvent,
4
- createSetStateEvent,
5
- isReplaceStateEvent,
6
- isSetStateEvent,
7
- isSnapshotStateEvent
8
- } from "./events.js";
9
- import {
10
- $createOperation,
11
- $processServerResponse,
12
- $resolveOperation,
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
- let reason;
89
- if (event.accepted || isSnapshotStateEvent(event)) {
90
- this.#applyAcceptedEvent(event);
91
- } else {
92
- reason = `Server rejected the operation with id '${event.id}'. See the server log for more details.`;
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
- [record?.id, event.id].filter(Boolean).forEach((id) => this[$resolveOperation](id, reason));
95
- }
96
- #applyAcceptedEvent(event) {
97
- if (isSetStateEvent(event) || isSnapshotStateEvent(event)) {
98
- this.value = event.value;
99
- } else if (isReplaceStateEvent(event)) {
100
- if (JSON.stringify(this.value) === JSON.stringify(event.expected)) {
101
- this.value = event.value;
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
- export {
107
- ValueSignal
108
- };
109
- //# sourceMappingURL=ValueSignal.js.map
62
+ //# sourceMappingURL=ValueSignal.js.map
@@ -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
@@ -1,2 +1 @@
1
1
  export * from '@preact/signals-react';
2
- //# sourceMappingURL=core.d.ts.map
package/core.js CHANGED
@@ -1,2 +1,2 @@
1
- export * from "@preact/signals-react";
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 "nanoid";
2
- function createSetStateEvent(value, signalId, parentSignalId) {
3
- return {
4
- id: signalId ?? nanoid(),
5
- type: "set",
6
- value,
7
- accepted: false,
8
- ...parentSignalId !== void 0 ? { parentSignalId } : {}
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
- return {
13
- id: signalId ?? nanoid(),
14
- type: "replace",
15
- value,
16
- expected,
17
- accepted: false,
18
- ...parentSignalId !== void 0 ? { parentSignalId } : {}
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
- return {
23
- id: nanoid(),
24
- type: "increment",
25
- value: delta,
26
- accepted: false
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
- return {
31
- id: nanoid(),
32
- type: "insert",
33
- value,
34
- position: "last",
35
- accepted: false
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
- return {
40
- id: nanoid(),
41
- type: "remove",
42
- entryId,
43
- value: void 0,
44
- accepted: false
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
- return typeof event === "object" && event !== null && typeof event.id === "string" && typeof event.type === "string" && typeof event.value !== "undefined" && typeof event.accepted === "boolean";
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
- return isStateEvent(event) && event.type === "snapshot";
55
+ export function isSnapshotStateEvent(event) {
56
+ return isStateEvent(event) && event.type === 'snapshot';
52
57
  }
53
- function isSetStateEvent(event) {
54
- return isStateEvent(event) && event.type === "set";
58
+ export function isSetStateEvent(event) {
59
+ return isStateEvent(event) && event.type === 'set';
55
60
  }
56
- function isReplaceStateEvent(event) {
57
- return isStateEvent(event) && typeof event.expected !== "undefined" && event.type === "replace";
61
+ export function isReplaceStateEvent(event) {
62
+ return (isStateEvent(event) && typeof event.expected !== 'undefined' && event.type === 'replace');
58
63
  }
59
- function isIncrementStateEvent(event) {
60
- return isStateEvent(event) && event.type === "increment";
64
+ export function isIncrementStateEvent(event) {
65
+ return isStateEvent(event) && event.type === 'increment';
61
66
  }
62
- function isListSnapshotStateEvent(event) {
63
- return typeof event === "object" && event !== null && typeof event.id === "string" && event.type === "snapshot" && event.entries instanceof Array && typeof event.accepted !== "undefined";
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
- return isStateEvent(event) && event.type === "insert" && event.position === "last";
75
+ export function isInsertLastStateEvent(event) {
76
+ return isStateEvent(event) && event.type === 'insert' && event.position === 'last';
67
77
  }
68
- function isRemoveStateEvent(event) {
69
- return typeof event === "object" && event !== null && typeof event.id === "string" && event.type === "remove" && typeof event.entryId === "string" && typeof event.value === "undefined";
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
- export {
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
@@ -6,4 +6,3 @@ export { ListSignal } from './ListSignal.js';
6
6
  export type { OperationSubscription } from './ValueSignal.js';
7
7
  export { FullStackSignal } from './FullStackSignal.js';
8
8
  export type { Operation } from './FullStackSignal.js';
9
- //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,13 +1,7 @@
1
- import "./polyfills.js";
2
- export * from "./core.js";
3
- import { NumberSignal } from "./NumberSignal.js";
4
- import { ValueSignal } from "./ValueSignal.js";
5
- import { ListSignal } from "./ListSignal.js";
6
- import { FullStackSignal } from "./FullStackSignal.js";
7
- export {
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-alpha9",
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": "concurrently npm: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": "karma start ../../../karma.config.cjs --port 9881",
27
- "test:coverage": "npm run test -- --coverage",
28
- "test:watch": "npm run test -- --watch",
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": "^3.0.1",
50
- "@vaadin/hilla-frontend": "24.7.0-alpha9",
51
- "nanoid": "^5.0.9"
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
@@ -8,4 +8,3 @@ declare global {
8
8
  }
9
9
  }
10
10
  export {};
11
- //# sourceMappingURL=polyfills.d.ts.map
package/polyfills.js CHANGED
@@ -1,15 +1,16 @@
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, reject, promise };
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
- //# sourceMappingURL=polyfills.js.map
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
- export declare class Signal<T> extends _Signal<T> {
5
- protected S(node: unknown): void;
6
- protected U(node: unknown): void;
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
@@ -0,0 +1,2 @@
1
+ import { Signal as _Signal } from '@preact/signals-react';
2
+ //# sourceMappingURL=types.js.map