UNPKG

@gravity-ui/graph

Version:

Modern graph editor component

135 lines (134 loc) 6.2 kB
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; }