@vaadin/hilla-react-signals
Version:
Signals for Hilla React
121 lines • 4.7 kB
JavaScript
import { CollectionSignal } from './CollectionSignal.js';
import { createInsertLastStateEvent, createRemoveStateEvent, isInsertLastStateEvent, isListSnapshotStateEvent, isRemoveStateEvent, } from './events.js';
import { $createOperation, $processServerResponse, $resolveOperation, $setValueQuietly, $update, } from './FullStackSignal.js';
import { ValueSignal } from './ValueSignal.js';
export class ListSignal extends CollectionSignal {
#head;
#tail;
#values = new Map();
constructor(config) {
const initialValue = [];
super(initialValue, config);
}
#computeItems() {
let current = this.#head;
const result = [];
while (current !== undefined) {
const entry = this.#values.get(current);
result.push(entry.value);
current = entry.next;
}
return result;
}
[$processServerResponse](event) {
if (!event.accepted) {
this[$resolveOperation](event.id, `Server rejected the operation with id '${event.id}'. See the server log for more details.`);
return;
}
if (isListSnapshotStateEvent(event)) {
this.#handleSnapshotEvent(event);
}
else if (isInsertLastStateEvent(event)) {
this.#handleInsertLastUpdate(event);
}
else if (isRemoveStateEvent(event)) {
this.#handleRemoveUpdate(event);
}
this[$resolveOperation](event.id);
}
#handleInsertLastUpdate(event) {
if (event.entryId === undefined) {
throw new Error('Unexpected state: Entry id should be defined when insert last event is accepted');
}
const valueSignal = new ValueSignal(event.value, { ...this.server.config, parentClientSignalId: this.id }, event.entryId);
const newEntry = { id: valueSignal.id, value: valueSignal };
if (this.#head === undefined) {
this.#head = newEntry.id;
this.#tail = this.#head;
}
else {
const tailEntry = this.#values.get(this.#tail);
tailEntry.next = newEntry.id;
newEntry.prev = this.#tail;
this.#tail = newEntry.id;
}
this.#values.set(valueSignal.id, newEntry);
this[$setValueQuietly](this.#computeItems());
}
#handleRemoveUpdate(event) {
const entryToRemove = this.#values.get(event.entryId);
if (entryToRemove === undefined) {
return;
}
this.#values.delete(event.id);
if (this.#head === entryToRemove.id) {
if (entryToRemove.next === undefined) {
this.#head = undefined;
this.#tail = undefined;
}
else {
const newHead = this.#values.get(entryToRemove.next);
this.#head = newHead.id;
newHead.prev = undefined;
}
}
else {
const prevEntry = this.#values.get(entryToRemove.prev);
const nextEntry = entryToRemove.next !== undefined ? this.#values.get(entryToRemove.next) : undefined;
if (nextEntry === undefined) {
this.#tail = prevEntry.id;
prevEntry.next = undefined;
}
else {
prevEntry.next = nextEntry.id;
nextEntry.prev = prevEntry.id;
}
}
this[$setValueQuietly](this.#computeItems());
}
#handleSnapshotEvent(event) {
event.entries.forEach((entry) => {
this.#values.set(entry.id, {
id: entry.id,
prev: entry.prev,
next: entry.next,
value: new ValueSignal(entry.value, { ...this.server.config, parentClientSignalId: this.id }, entry.id),
});
if (entry.prev === undefined) {
this.#head = entry.id;
}
if (entry.next === undefined) {
this.#tail = entry.id;
}
});
this[$setValueQuietly](this.#computeItems());
}
insertLast(value) {
const event = createInsertLastStateEvent(value);
const promise = this[$update](event);
return this[$createOperation]({ id: event.id, promise });
}
remove(item) {
const entryToRemove = this.#values.get(item.id);
if (entryToRemove === undefined) {
return { result: Promise.resolve() };
}
const removeEvent = createRemoveStateEvent(entryToRemove.value.id);
const promise = this[$update](removeEvent);
return this[$createOperation]({ id: removeEvent.id, promise });
}
}
//# sourceMappingURL=ListSignal.js.map