@gravity-ui/graph
Version:
Modern graph editor component
135 lines (134 loc) • 6.2 kB
TypeScript
import type { ReadonlySignal, Signal } from "@preact/signals-core";
import type { GraphComponent } from "../../components/canvas/GraphComponent";
import type { SelectionService } from "./SelectionService";
import { ESelectionStrategy, ISelectionBucket, TSelectionDiff, TSelectionEntity, TSelectionEntityId } from "./types";
/**
* @abstract
* @template IDType The type of the unique identifier for the entities managed by this bucket (e.g., `string`, `number`).
* @template TEntity The type of the entity that IDs resolve to. Must extend TSelectionEntity (GraphComponent or IEntityWithComponent).
*
* Base class for selection buckets.
*
* Selection buckets are fundamental components of the {@link SelectionService}.
* Each bucket is responsible for managing the selection state (the set of selected IDs)
* for a specific entity type within the graph (e.g., blocks, connections, anchors, or custom entities).
*
* This abstract class provides a common structure and basic functionality for all selection buckets,
* including managing the internal reactive state of selected IDs using `@preact/signals-core`
* and handling interaction with the central {@link SelectionService}.
*
* When creating a custom selection bucket, you should extend this class (or its concrete implementations
* like {@link MultipleSelectionBucket} or {@link SingleSelectionBucket}) and define the specific
* logic for selecting and deselecting entities of its type.
*
* @example
* ```typescript
* class MySelectionBucket extends BaseSelectionBucket<string, MyEntity> {
* public updateSelection(ids: string[], select: boolean, strategy: ESelectionStrategy, silent?: boolean): void {
* // implementation
* }
* }
* ```
*
* @implements {ISelectionBucket<IDType, TEntity>}
* @see {@link SelectionService}
* @see {@link ISelectionBucket}
* @see {@link MultipleSelectionBucket}
* @see {@link SingleSelectionBucket}
* @see {@linkplain ../../docs/system/selection-manager.md SelectionManager Documentation} for more details on selection architecture.
*/
export declare abstract class BaseSelectionBucket<IDType extends TSelectionEntityId, TEntity extends TSelectionEntity = TSelectionEntity> implements ISelectionBucket<IDType, TEntity> {
readonly entityType: string;
protected onSelectionChange: (payload: TSelectionDiff<IDType>, defaultAction: (rewritenIds?: Set<IDType>) => void) => void | boolean;
isRelatedElement?: (element: GraphComponent) => boolean;
protected resolver?: (ids: IDType[]) => TEntity[];
protected readonly $selectedIds: Signal<Set<IDType>>;
readonly $selected: ReadonlySignal<Set<IDType>>;
/**
* Computed signal that resolves selected IDs to their corresponding entities.
* Returns an empty array if no resolver function is provided.
*/
readonly $selectedEntities: ReadonlySignal<TEntity[]>;
/**
* Computed signal that resolves selected entities to their GraphComponent views.
* Works with entities that:
* - Are GraphComponent instances themselves
* - Implement IEntityWithComponent interface (have getViewComponent() method)
* Returns an empty array if entities cannot be resolved to components.
*/
readonly $selectedComponents: ReadonlySignal<GraphComponent[]>;
protected manager: SelectionService;
/**
* Check if an entity is a GraphComponent
*/
private isGraphComponent;
/**
* Check if an entity has getViewComponent method
*/
private hasViewComponent;
constructor(entityType: string, onSelectionChange?: (payload: TSelectionDiff<IDType>, defaultAction: (rewritenIds?: Set<IDType>) => void) => void | boolean, isRelatedElement?: (element: GraphComponent) => boolean, resolver?: (ids: IDType[]) => TEntity[]);
/**
* Attaches the bucket to the manager
*
* @param manager {SelectionService} - The manager to attach to
* @returns void
*/
attachToManager(manager: SelectionService): void;
/**
* Detaches the bucket from the manager
* @param manager {SelectionService} - The manager to detach from
* @returns void
*/
detachFromManager(manager: SelectionService): void;
/**
* Selects the given ids
*
* @param ids {IDType[]} - The ids to select
* @param strategy {ESelectionStrategy} - The strategy to use
* @param silent {boolean} - Whether to suppress the selection change event
* @returns void
*/
select(ids: IDType[], strategy?: ESelectionStrategy, silent?: boolean): void;
/**
* Deselects the given ids
* Passed ids will be deselected with strategy SUBTRACT
*
* @param ids {IDType[]} - The ids to deselect
* @param silent {boolean} - Whether to suppress the selection change event
* @returns void
*/
deselect(ids: IDType[], silent?: boolean): void;
/**
* Updates the selection
* @param ids - The ids to update
* @param select - Whether to select or deselect
* @param strategy - The strategy to use
* @param silent - Whether to suppress the selection change event
*/
abstract updateSelection(ids: IDType[], select: boolean, strategy: ESelectionStrategy, silent?: boolean): void;
/**
* Resets the selection
* All selected ids will be deselected with strategy SUBTRACT
*
* @returns void
*/
reset(): void;
/**
* Checks if the given id is selected
*
* @param id {IDType} - The id to check
* @returns boolean
*/
isSelected(id: IDType): boolean;
/**
* Applies the selection
* Generate diff between new and current selected ids and run onSelectionChange callback
* If silent is true, the nextSelection state will be applied immediately, otherwise it will be applied after the callback is executed and
*
* @param newSelectedIds {Set<IDType>} - The new selected ids
* @param currentSelectedIds {Set<IDType>} - The current selected ids
* @param silent {boolean} - Whether to suppress the selection change event
* @returns void
*/
protected applySelection(newSelectedIds: Set<IDType>, currentSelectedIds: Set<IDType>, silent?: boolean): void;
}