← Files Biological Sequence & Alignment ViewerARCHIVED FILE

src/sequence/interaction-state.ts

1.78 KB · Sep 30, 2026 · 23:01 UTC

↓ Download file

import type { SequenceFeature, SequenceSelection } from "./types";

export type SequenceInteractionState = {
  activeSearchHitIndex: number;
  focusCoordinate?: number;
  selectedFeature?: SequenceFeature;
  selectedRecordId: string;
  selection?: SequenceSelection;
};

export type SequenceInteractionAction =
  | { recordId: string; type: "select-record" }
  | { selection: SequenceSelection; type: "select-range" }
  | { coordinate: number | undefined; type: "set-focus" }
  | { feature: SequenceFeature | undefined; type: "set-feature" }
  | { index: number; type: "set-search-hit" }
  | { type: "reset-search" }
  | { type: "clear-selection" };

export function createSequenceInteractionState(
  selectedRecordId: string,
): SequenceInteractionState {
  return { activeSearchHitIndex: 0, selectedRecordId };
}

export function sequenceInteractionReducer(
  state: SequenceInteractionState,
  action: SequenceInteractionAction,
): SequenceInteractionState {
  switch (action.type) {
    case "select-record":
      return action.recordId === state.selectedRecordId
        ? state
        : createSequenceInteractionState(action.recordId);
    case "select-range":
      return {
        ...state,
        focusCoordinate: action.selection.start,
        selection: action.selection,
      };
    case "set-focus":
      return { ...state, focusCoordinate: action.coordinate };
    case "set-feature":
      return { ...state, selectedFeature: action.feature };
    case "set-search-hit":
      return { ...state, activeSearchHitIndex: Math.max(0, action.index) };
    case "reset-search":
      return { ...state, activeSearchHitIndex: 0 };
    case "clear-selection":
      return {
        ...state,
        focusCoordinate: undefined,
        selectedFeature: undefined,
        selection: undefined,
      };
  }
}

SHA-256: a715f5bc9314186a6843ba469aec61977165294be1f24418b469451e1f350b95