@vaadin/hilla-react-signals
Version:
Signals for Hilla React
62 lines • 2.79 kB
JavaScript
import { nanoid } from 'nanoid';
import { createReplaceStateEvent, createSetStateEvent, isReplaceStateEvent, isSetStateEvent, isSnapshotStateEvent, } from './events.js';
import { $createOperation, $processServerResponse, $resolveOperation, $setValueQuietly, $update, FullStackSignal, } from './FullStackSignal.js';
export class ValueSignal extends FullStackSignal {
#pendingRequests = new Map();
set(value) {
const { parentClientSignalId } = this.server.config;
const signalId = parentClientSignalId !== undefined ? this.id : undefined;
const event = createSetStateEvent(value, signalId, parentClientSignalId);
const promise = this[$update](event);
this[$setValueQuietly](value);
return this[$createOperation]({ id: event.id, promise });
}
replace(expected, newValue) {
const { parentClientSignalId } = this.server.config;
const signalId = parentClientSignalId !== undefined ? this.id : undefined;
const event = createReplaceStateEvent(expected, newValue, signalId, parentClientSignalId);
const promise = this[$update](event);
return this[$createOperation]({ id: event.id, promise });
}
update(callback) {
const newValue = callback(this.value);
const event = createReplaceStateEvent(this.value, newValue);
const promise = this[$update](event);
const pendingRequest = { id: nanoid(), callback, canceled: false };
this.#pendingRequests.set(event.id, pendingRequest);
return {
...this[$createOperation]({ id: pendingRequest.id, promise }),
cancel: () => {
pendingRequest.canceled = true;
},
};
}
[$processServerResponse](event) {
const record = this.#pendingRequests.get(event.id);
if (record) {
this.#pendingRequests.delete(event.id);
if (!(event.accepted || record.canceled)) {
this.update(record.callback);
}
}
let reason;
if (event.accepted || isSnapshotStateEvent(event)) {
this.#applyAcceptedEvent(event);
}
else {
reason = `Server rejected the operation with id '${event.id}'. See the server log for more details.`;
}
[record?.id, event.id].filter(Boolean).forEach((id) => this[$resolveOperation](id, reason));
}
#applyAcceptedEvent(event) {
if (isSetStateEvent(event) || isSnapshotStateEvent(event)) {
this.value = event.value;
}
else if (isReplaceStateEvent(event)) {
if (JSON.stringify(this.value) === JSON.stringify(event.expected)) {
this.value = event.value;
}
}
}
}
//# sourceMappingURL=ValueSignal.js.map