canvas-website/src/collections/BaseCollection.ts

107 lines
2.9 KiB
TypeScript

import { Editor, TLShape, TLShapeId } from '@tldraw/tldraw';
/**
* A PoC abstract collections class for @tldraw.
*/
export abstract class BaseCollection {
/** A unique identifier for the collection. */
abstract id: string;
/** A map containing the shapes that belong to this collection, keyed by their IDs. */
protected shapes: Map<TLShapeId, TLShape> = new Map();
/** A reference to the \@tldraw Editor instance. */
protected editor: Editor;
/** A set of listeners to be notified when the collection changes. */
private listeners = new Set<() => void>();
// TODO: Maybe pass callback to replace updateShape so only CollectionProvider can call it
public constructor(editor: Editor) {
this.editor = editor;
}
/**
* Called when shapes are added to the collection.
* @param shapes The shapes being added to the collection.
*/
protected onAdd(_shapes: TLShape[]): void { }
/**
* Called when shapes are removed from the collection.
* @param shapes The shapes being removed from the collection.
*/
protected onRemove(_shapes: TLShape[]) { }
/**
* Called when the membership of the collection changes (i.e., when shapes are added or removed).
*/
protected onMembershipChange() { }
/**
* Called when the properties of a shape belonging to the collection change.
* @param prev The previous version of the shape before the change.
* @param next The updated version of the shape after the change.
*/
protected onShapeChange(_prev: TLShape, _next: TLShape) { }
/**
* Adds the specified shapes to the collection.
* @param shapes The shapes to add to the collection.
*/
public add(shapes: TLShape[]) {
shapes.forEach(shape => {
this.shapes.set(shape.id, shape)
});
this.onAdd(shapes);
this.onMembershipChange();
this.notifyListeners();
}
/**
* Removes the specified shapes from the collection.
* @param shapes The shapes to remove from the collection.
*/
public remove(shapes: TLShape[]) {
shapes.forEach(shape => {
this.shapes.delete(shape.id);
});
this.onRemove(shapes);
this.onMembershipChange();
this.notifyListeners();
}
/**
* Clears all shapes from the collection.
*/
public clear() {
this.remove([...this.shapes.values()])
}
/**
* Returns the map of shapes in the collection.
* @returns The map of shapes in the collection, keyed by their IDs.
*/
public getShapes(): Map<TLShapeId, TLShape> {
return this.shapes;
}
public get size(): number {
return this.shapes.size;
}
public _onShapeChange(prev: TLShape, next: TLShape) {
this.shapes.set(next.id, next)
this.onShapeChange(prev, next)
this.notifyListeners();
}
private notifyListeners() {
for (const listener of this.listeners) {
listener();
}
}
public subscribe(listener: () => void): () => void {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
}