@tldraw/store
Version:
tldraw infinite canvas SDK (store).
145 lines (144 loc) • 4.2 kB
JavaScript
class IncrementalSetConstructor {
constructor(previousValue) {
this.previousValue = previousValue;
}
/**
* The next value of the set.
*
* @internal
*/
nextValue;
/**
* The diff of the set.
*
* @internal
*/
diff;
/**
* Gets the result of the incremental set construction if any changes were made.
* Returns undefined if no additions or removals occurred.
*
* @returns An object containing the final set value and the diff of changes,
* or undefined if no changes were made
*
* @example
* ```ts
* const constructor = new IncrementalSetConstructor(new Set(['a', 'b']))
* constructor.add('c')
*
* const result = constructor.get()
* // result = {
* // value: Set(['a', 'b', 'c']),
* // diff: { added: Set(['c']) }
* // }
* ```
*
* @public
*/
get() {
const numRemoved = this.diff?.removed?.size ?? 0;
const numAdded = this.diff?.added?.size ?? 0;
if (numRemoved === 0 && numAdded === 0) {
return void 0;
}
return { value: this.nextValue, diff: this.diff };
}
/**
* Add an item to the set.
*
* @param item - The item to add.
* @param wasAlreadyPresent - Whether the item was already present in the set.
* @internal
*/
_add(item, wasAlreadyPresent) {
this.nextValue ??= new Set(this.previousValue);
this.nextValue.add(item);
this.diff ??= {};
if (wasAlreadyPresent) {
this.diff.removed?.delete(item);
} else {
this.diff.added ??= /* @__PURE__ */ new Set();
this.diff.added.add(item);
}
}
/**
* Adds an item to the set. If the item was already present in the original set
* and was previously removed during this construction, it will be restored.
* If the item is already present and wasn't removed, this is a no-op.
*
* @param item - The item to add to the set
*
* @example
* ```ts
* const constructor = new IncrementalSetConstructor(new Set(['a', 'b']))
* constructor.add('c') // Adds new item
* constructor.add('a') // No-op, already present
* constructor.remove('b')
* constructor.add('b') // Restores previously removed item
* ```
*
* @public
*/
add(item) {
const wasAlreadyPresent = this.previousValue.has(item);
if (wasAlreadyPresent) {
const wasRemoved = this.diff?.removed?.has(item);
if (!wasRemoved) return;
return this._add(item, wasAlreadyPresent);
}
const isCurrentlyPresent = this.nextValue?.has(item);
if (isCurrentlyPresent) return;
this._add(item, wasAlreadyPresent);
}
/**
* Remove an item from the set.
*
* @param item - The item to remove.
* @param wasAlreadyPresent - Whether the item was already present in the set.
* @internal
*/
_remove(item, wasAlreadyPresent) {
this.nextValue ??= new Set(this.previousValue);
this.nextValue.delete(item);
this.diff ??= {};
if (wasAlreadyPresent) {
this.diff.removed ??= /* @__PURE__ */ new Set();
this.diff.removed.add(item);
} else {
this.diff.added?.delete(item);
}
}
/**
* Removes an item from the set. If the item wasn't present in the original set
* and was added during this construction, it will be removed from the added diff.
* If the item is not present at all, this is a no-op.
*
* @param item - The item to remove from the set
*
* @example
* ```ts
* const constructor = new IncrementalSetConstructor(new Set(['a', 'b']))
* constructor.remove('a') // Removes existing item
* constructor.remove('c') // No-op, not present
* constructor.add('d')
* constructor.remove('d') // Removes recently added item
* ```
*
* @public
*/
remove(item) {
const wasAlreadyPresent = this.previousValue.has(item);
if (!wasAlreadyPresent) {
const wasAdded = this.diff?.added?.has(item);
if (!wasAdded) return;
return this._remove(item, wasAlreadyPresent);
}
const hasAlreadyBeenRemoved = this.diff?.removed?.has(item);
if (hasAlreadyBeenRemoved) return;
this._remove(item, wasAlreadyPresent);
}
}
export {
IncrementalSetConstructor
};
//# sourceMappingURL=IncrementalSetConstructor.mjs.map