@vaadin/hilla-react-signals 24.6.0-alpha3 → 24.6.0-alpha4

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.d.ts CHANGED
@@ -21,7 +21,7 @@ export declare class ValueSignal<T> extends FullStackSignal<T> {
21
21
  *
22
22
  * @param value - The new value.
23
23
  */
24
- set(value: T): void;
24
+ set(value: T): Operation;
25
25
  /**
26
26
  * Replaces the value with a new one only if the current value is equal to the
27
27
  * expected value.
@@ -1 +1 @@
1
- {"version":3,"file":"ValueSignal.d.ts","sourceRoot":"","sources":["src/ValueSignal.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,sBAAsB,EAGtB,eAAe,EACf,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAO9B;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,SAAS;IACtD,MAAM,IAAI,IAAI,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,WAAW,CAAC,CAAC,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;;IAGpD;;;;;;;;;OASG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAInB;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS;IAQ5C;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,qBAAqB;cAcrC,CAAC,sBAAsB,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CA8BrE"}
1
+ {"version":3,"file":"ValueSignal.d.ts","sourceRoot":"","sources":["src/ValueSignal.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,sBAAsB,EAItB,eAAe,EACf,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAO9B;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,SAAS;IACtD,MAAM,IAAI,IAAI,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,WAAW,CAAC,CAAC,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;;IAGpD;;;;;;;;;OASG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,SAAS;IASxB;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,SAAS;IAQ5C;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,qBAAqB;cAcrC,CAAC,sBAAsB,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CA8BrE"}
package/ValueSignal.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { nanoid } from "nanoid";
2
2
  import {
3
3
  createReplaceStateEvent,
4
+ createSetStateEvent,
4
5
  isReplaceStateEvent,
5
6
  isSetStateEvent,
6
7
  isSnapshotStateEvent
@@ -9,6 +10,7 @@ import {
9
10
  $createOperation,
10
11
  $processServerResponse,
11
12
  $resolveOperation,
13
+ $setValueQuietly,
12
14
  $update,
13
15
  FullStackSignal
14
16
  } from "./FullStackSignal.js";
@@ -25,7 +27,12 @@ class ValueSignal extends FullStackSignal {
25
27
  * @param value - The new value.
26
28
  */
27
29
  set(value) {
28
- this.value = value;
30
+ const { parentClientSignalId } = this.server.config;
31
+ const signalId = parentClientSignalId !== void 0 ? this.id : void 0;
32
+ const event = createSetStateEvent(value, signalId, parentClientSignalId);
33
+ const promise = this[$update](event);
34
+ this[$setValueQuietly](value);
35
+ return this[$createOperation]({ id: event.id, promise });
29
36
  }
30
37
  /**
31
38
  * Replaces the value with a new one only if the current value is equal to the
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["src/ValueSignal.ts"],
4
- "sourcesContent": ["import { nanoid } from 'nanoid';\nimport {\n createReplaceStateEvent,\n isReplaceStateEvent,\n isSetStateEvent,\n isSnapshotStateEvent,\n type StateEvent,\n} from './events.js';\nimport {\n $createOperation,\n $processServerResponse,\n $resolveOperation,\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 */\n set(value: T): void {\n this.value = value;\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, 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';\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,OAEK;AACP;AAAA,EACE;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,EAYtE,IAAI,OAAgB;AAClB,SAAK,QAAQ;AAAA,EACf;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,EAeA,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;AAAA,IACX;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;",
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 */\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, 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';\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,EAYtE,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,EAeA,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;AAAA,IACX;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
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/hilla-react-signals",
3
- "version": "24.6.0-alpha3",
3
+ "version": "24.6.0-alpha4",
4
4
  "description": "Signals for Hilla React",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -47,7 +47,7 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "@preact/signals-react": "^2.0.0",
50
- "@vaadin/hilla-frontend": "24.6.0-alpha3",
50
+ "@vaadin/hilla-frontend": "24.6.0-alpha4",
51
51
  "nanoid": "^5.0.7"
52
52
  },
53
53
  "peerDependencies": {