loom-browser 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/loom-react.esm.js +3810 -3099
  2. package/dist/loom-react.esm.min.js +1 -1
  3. package/dist/loom-react.esm.min.js.map +1 -1
  4. package/dist/loom-worker.js +191 -137
  5. package/dist/loom-worker.min.js +1 -1
  6. package/dist/loom-worker.min.js.map +1 -1
  7. package/dist/loom.esm.js +3641 -2883
  8. package/dist/loom.esm.min.js +1 -1
  9. package/dist/loom.esm.min.js.map +1 -1
  10. package/dist/loom.js +3652 -2886
  11. package/dist/loom.min.js +1 -1
  12. package/dist/loom.min.js.map +1 -1
  13. package/dist/tsconfig.src.tsbuildinfo +1 -1
  14. package/dist/types/browser/dom/browserExport.d.ts +32 -0
  15. package/dist/types/browser/dom/contextMenu.d.ts +64 -0
  16. package/dist/types/browser/dom/contextMenuManager.d.ts +49 -0
  17. package/dist/types/browser/dom/defaultProviders.d.ts +23 -0
  18. package/dist/types/browser/dom/genomeBrowser.d.ts +171 -0
  19. package/dist/types/browser/dom/pointerEventManager.d.ts +109 -0
  20. package/dist/types/browser/dom/roiOverlayManager.d.ts +38 -0
  21. package/dist/types/browser/dom/svgFeatureOverlay.d.ts +27 -0
  22. package/dist/types/browser/headless/errors.d.ts +10 -0
  23. package/dist/types/browser/headless/headlessGenomeBrowser.d.ts +391 -0
  24. package/dist/types/browser/headless/roiManager.d.ts +47 -0
  25. package/dist/types/browser/headless/session.d.ts +45 -0
  26. package/dist/types/browser/headless/trackDataManager.d.ts +53 -0
  27. package/dist/types/browser/headless/trackFactories.d.ts +145 -0
  28. package/dist/types/browser/index.d.ts +24 -0
  29. package/dist/types/browserExport.d.ts +32 -0
  30. package/dist/types/commandDispatcher.d.ts +1 -1
  31. package/dist/types/contextMenuManager.d.ts +49 -0
  32. package/dist/types/data/searchService.d.ts +24 -0
  33. package/dist/types/dataSourceWorkerProvider.d.ts +3 -3
  34. package/dist/types/dataSources/bigWigDataSource.d.ts +2 -2
  35. package/dist/types/dataSources/config.d.ts +40 -0
  36. package/dist/types/dataSources/configureDataSource.d.ts +17 -0
  37. package/dist/types/dataSources/createDataSource.d.ts +14 -0
  38. package/dist/types/dataSources/geneDataSource.d.ts +4 -3
  39. package/dist/types/dataSources/gtxDataSource.d.ts +2 -2
  40. package/dist/types/dataSources/memoryDataSource.d.ts +2 -2
  41. package/dist/types/dataSources/sequenceDataSource.d.ts +4 -1
  42. package/dist/types/dataSources/textFeatureSource.d.ts +4 -2
  43. package/dist/types/dataSources/wholeGenomeUtils.d.ts +37 -0
  44. package/dist/types/defaultProviders.d.ts +23 -0
  45. package/dist/types/errors.d.ts +10 -0
  46. package/dist/types/formats/featureParser.d.ts +1 -1
  47. package/dist/types/genomeBrowser.d.ts +18 -91
  48. package/dist/types/headlessGenomeBrowser.d.ts +88 -225
  49. package/dist/types/index.d.ts +21 -14
  50. package/dist/types/io/binaryParser.d.ts +0 -1
  51. package/dist/types/logger.d.ts +20 -0
  52. package/dist/types/pointerEventManager.d.ts +109 -0
  53. package/dist/types/react/GenomeBrowserContext.d.ts +1 -1
  54. package/dist/types/react/LoomBrowser.d.ts +4 -4
  55. package/dist/types/react/hooks/useBrowserEvent.d.ts +1 -1
  56. package/dist/types/react/hooks/useGenomeBrowser.d.ts +1 -1
  57. package/dist/types/react/hooks/useTrackManager.d.ts +1 -1
  58. package/dist/types/react/tracks/BedTrack.d.ts +7 -7
  59. package/dist/types/react/ui/ChromosomeSelect.d.ts +1 -1
  60. package/dist/types/react/ui/ExportControls.d.ts +1 -1
  61. package/dist/types/react/ui/LocusInput.d.ts +1 -1
  62. package/dist/types/react/ui/Navbar.d.ts +1 -1
  63. package/dist/types/react/ui/WindowSize.d.ts +1 -1
  64. package/dist/types/react/ui/ZoomControls.d.ts +1 -1
  65. package/dist/types/remoteProtocol.d.ts +1 -1
  66. package/dist/types/roiManager.d.ts +47 -0
  67. package/dist/types/roiOverlayManager.d.ts +38 -0
  68. package/dist/types/stateProjection.d.ts +1 -1
  69. package/dist/types/trackDataManager.d.ts +48 -0
  70. package/dist/types/trackFactories.d.ts +140 -0
  71. package/dist/types/trackSelector.d.ts +1 -1
  72. package/dist/types/tracks/annotation/annotationTrackCanvas.d.ts +0 -1
  73. package/dist/types/tracks/annotation/config.d.ts +61 -0
  74. package/dist/types/tracks/baseTrackCanvas.d.ts +10 -0
  75. package/dist/types/tracks/configDiff.d.ts +14 -0
  76. package/dist/types/tracks/interaction/config.d.ts +40 -0
  77. package/dist/types/tracks/ruler/config.d.ts +24 -0
  78. package/dist/types/tracks/sequence/config.d.ts +56 -0
  79. package/dist/types/tracks/sequence/sequenceTrackCanvas.d.ts +3 -0
  80. package/dist/types/tracks/wig/config.d.ts +77 -0
  81. package/dist/types/types/igvCompat.d.ts +36 -0
  82. package/dist/types/types.d.ts +48 -284
  83. package/dist/types/ui/components/LoomBrowserShell.d.ts +2 -2
  84. package/dist/types/ui/components/LoomChromosomeSelect.d.ts +1 -1
  85. package/dist/types/ui/components/LoomContextMenu.d.ts +1 -0
  86. package/dist/types/ui/components/LoomExportControls.d.ts +1 -1
  87. package/dist/types/ui/components/LoomLocusInput.d.ts +1 -1
  88. package/dist/types/ui/components/LoomNavbar.d.ts +1 -1
  89. package/dist/types/ui/components/LoomWindowSize.d.ts +1 -1
  90. package/dist/types/ui/components/LoomZoomControls.d.ts +1 -1
  91. package/dist/types/undoManager.d.ts +49 -0
  92. package/dist/types/worker/dataSourceRegistry.d.ts +2 -2
  93. package/dist/types/worker/serializedError.d.ts +16 -0
  94. package/dist/types/worker/taskTimeout.d.ts +21 -0
  95. package/dist/types/worker/webWorkerPool.d.ts +5 -2
  96. package/dist/types/worker/webWorkerProvider.d.ts +3 -0
  97. package/dist/types/workerDataSource.d.ts +2 -2
  98. package/dist/types/workerProvider.d.ts +2 -2
  99. package/package.json +1 -1
@@ -9,6 +9,12 @@
9
9
  * Ruler tracks get special treatment: dragging on a ruler creates a selection
10
10
  * overlay (sweep-to-zoom) instead of panning.
11
11
  *
12
+ * Delegates to focused single-responsibility modules:
13
+ * - PointerEventManager: drag/pan/sweep/click/hover/wheel/reorder
14
+ * - ROIOverlayManager: DOM-based ROI region rendering
15
+ * - ContextMenuManager: right-click context menus for tracks and ROIs
16
+ * - browserExport: SVG/PNG export utilities
17
+ *
12
18
  * Usage:
13
19
  * const browser = new GenomeBrowser(container, {
14
20
  * locus: { chr: 'chr17', start: 7668000, end: 7688000 },
@@ -78,42 +84,17 @@ export interface GenomeBrowserOptions extends HeadlessGenomeBrowserOptions {
78
84
  export declare class GenomeBrowser extends HeadlessGenomeBrowser {
79
85
  private container;
80
86
  private interactive;
81
- private isDragging;
82
- private lastPointerX;
83
- private isSweeping;
84
- private sweepStartX;
85
- private sweepOverlay;
86
- private sweepRulerCanvas;
87
- private pointerDownX;
88
- private pointerDownY;
89
- private pointerDownTarget;
90
- private lastClickTime;
91
- private lastClickX;
92
- private lastClickY;
93
- private singleClickTimer;
94
- private hoverThrottleId;
95
- private _rafId;
96
87
  private resizeObserver;
97
88
  private trackRows;
98
- private handleContextMenu;
99
- private inputDialog;
100
89
  private remoteConnection;
101
- private reorderDragTrack;
102
- private reorderDragRow;
103
- private reorderHandlers;
104
- private handlePointerDown;
105
- private handlePointerMove;
106
- private handlePointerUp;
107
- private handleMouseMove;
108
- private handleMouseLeave;
109
- private handleDocMouseDown;
110
- private handleWheel;
111
- private wheelRafId;
112
- private roiOverlayContainer;
113
- private roiElements;
114
90
  private featureOverlays;
115
91
  /** Worker provider auto-created by `workers` option. Disposed on cleanup. */
116
92
  private ownedWorkerProvider;
93
+ private handleKeyDown;
94
+ private handleDocMouseDown;
95
+ private pointerManager;
96
+ private roiOverlayManager;
97
+ private contextMenuManager;
117
98
  constructor(container: HTMLElement, options: GenomeBrowserOptions);
118
99
  /** Build a DOM row for a track (axis column + viewport wrapper). */
119
100
  private _buildTrackRow;
@@ -133,7 +114,6 @@ export declare class GenomeBrowser extends HeadlessGenomeBrowser {
133
114
  loadSession(session: SessionConfig, options?: CreateTrackFromSessionOptions): void;
134
115
  /** Re-render all tracks, reading width from the DOM container. */
135
116
  render(): void;
136
- /** Clean up event listeners, remove canvases, and dispose headless core. */
137
117
  /**
138
118
  * Attach a remote WebSocket connection.
139
119
  * Incoming command messages are automatically dispatched.
@@ -151,70 +131,29 @@ export declare class GenomeBrowser extends HeadlessGenomeBrowser {
151
131
  private updateAxisContent;
152
132
  /**
153
133
  * Prepare an axis canvas at the correct size with DPR scaling,
154
- * then delegate to the given stateless render function.
134
+ * then delegate to the stateless render function.
155
135
  */
156
136
  private paintAxisCanvas;
157
137
  /** Check if a pointer event target is a ruler track canvas. */
158
138
  private isRulerCanvas;
159
- private createSweepOverlay;
160
- private removeSweepOverlay;
161
- private setupDragHandlers;
162
139
  /** Check if an event originated inside an overlay UI component (Shadow DOM) or ROI element. */
163
140
  private isOverlayTarget;
164
141
  /** Find the track whose canvas contains the given event target. */
165
142
  private findTrackForTarget;
166
- /** Canvas-relative coordinates from a mouse/pointer event. */
167
- private canvasCoords;
168
- private handleClick;
169
- private setupHoverHandlers;
170
- private teardownHoverHandlers;
171
- private setupContextMenuHandler;
172
- private teardownContextMenuHandler;
173
143
  /** Sync DOM after any sort (addTrack, addGeneTrack, etc.). */
174
144
  protected onTracksSorted(): void;
175
145
  /** Reorder DOM rows to match managedTracks order. */
176
146
  private syncDOMOrder;
177
- /** Set up drag-to-reorder pointer handlers on an axis div. */
178
- private setupReorderHandlers;
179
- /** Remove reorder handlers for a track. */
180
- private teardownReorderHandlers;
181
- private teardownDragHandlers;
182
- /**
183
- * Set up wheel event handling for trackpad pinch-to-zoom and scroll-wheel zoom.
184
- *
185
- * Trackpad pinch gestures on macOS/Chrome are reported as `wheel` events with
186
- * `ctrlKey: true` and `deltaY` indicating zoom direction. Regular scroll-wheel
187
- * events (ctrl+scroll) use the same mechanism. Both zoom around the pointer
188
- * position for natural, cursor-anchored zoom behavior.
189
- */
190
- private setupWheelHandler;
191
- private teardownWheelHandler;
192
- /** Ensure the ROI overlay container exists and is sized correctly. */
193
- private ensureROIOverlayContainer;
194
- /**
195
- * Render ROI overlays as DOM elements positioned over the track viewport.
196
- *
197
- * Creates/updates/removes DOM elements for each visible ROI.
198
- * DOM-based (not canvas) for easy hover/click interaction without
199
- * re-rendering track canvases.
200
- */
147
+ private setupUndoKeyboardHandler;
148
+ private teardownUndoKeyboardHandler;
149
+ private renderROIOverlays;
201
150
  /** Update all feature overlays after render. */
202
151
  private updateFeatureOverlays;
203
152
  /** Update the feature overlay for a single track. */
204
153
  private updateFeatureOverlay;
205
- private renderROIOverlays;
206
- /** Create a styled DOM element for an ROI region. */
207
- private createROIElement;
208
- /** Show context menu for an ROI. */
209
- private showROIContextMenu;
210
- /** Clean up ROI overlay elements. */
211
- private clearROIOverlay;
212
154
  /**
213
155
  * Export the current view as an SVG string, including axis columns.
214
- *
215
- * Overrides HeadlessGenomeBrowser.toSVG() to add axis rendering on the
216
- * left side of each track, matching igv.js Browser.toSVG() which calls
217
- * renderSVGAxis() for each TrackView (js/browser.ts lines 352-388).
156
+ * Overrides HeadlessGenomeBrowser.toSVG() to add axis rendering.
218
157
  */
219
158
  toSVG(options?: {
220
159
  width?: number;
@@ -222,23 +161,11 @@ export declare class GenomeBrowser extends HeadlessGenomeBrowser {
222
161
  }): string;
223
162
  /**
224
163
  * Export the current view as a PNG data URL.
225
- *
226
164
  * Pipeline: toSVG() → Blob → Image → Canvas (DPR-scaled) → toDataURL.
227
- * Matches igv.js Browser.savePNGtoFile() (js/browser.ts lines 407-440).
228
- *
229
- * Returns a promise that resolves to a `data:image/png;base64,...` string.
230
165
  */
231
166
  toPNG(): Promise<string>;
232
- /**
233
- * Download the current view as an SVG file.
234
- * Matches igv.js Browser.saveSVGtoFile() (js/browser.ts lines 390-405).
235
- */
167
+ /** Download the current view as an SVG file. */
236
168
  saveSVGtoFile(filename?: string): void;
237
- /**
238
- * Download the current view as a PNG file.
239
- * Matches igv.js Browser.savePNGtoFile() (js/browser.ts lines 407-440).
240
- */
169
+ /** Download the current view as a PNG file. */
241
170
  savePNGtoFile(filename?: string): Promise<void>;
242
- /** Trigger a file download via a temporary anchor element. */
243
- private downloadURL;
244
171
  }
@@ -1,8 +1,13 @@
1
1
  /**
2
2
  * Headless GenomeBrowser — pure data/navigation/caching core with zero DOM dependencies.
3
3
  *
4
- * Manages locus state, track coordination, data lifecycle (buffered fetch, caching,
5
- * abort), events, and theming. Can run in Node.js, workers, or any environment.
4
+ * Manages locus state, track coordination, data lifecycle, events, and theming.
5
+ * Can run in Node.js, workers, or any environment.
6
+ *
7
+ * Delegates to focused single-responsibility modules:
8
+ * - ROIManager: Region of Interest CRUD and spatial queries
9
+ * - TrackDataManager: fetch dedup, caching, abort, debounce
10
+ * - Track factories: convenience track creation (trackFactories.ts)
6
11
  *
7
12
  * The DOM-attached `GenomeBrowser` extends this class to add pointer events,
8
13
  * ResizeObserver, canvas stacking, and sweep-to-zoom.
@@ -16,7 +21,7 @@
16
21
  * browser.setLocus({ chr: 'chr17', start: 7670000, end: 7680000 })
17
22
  * browser.dispose()
18
23
  */
19
- import type { Locus, Track, DataSource, FeatureCacheEntry, SessionConfig, TrackSessionConfig, DataSourceConfig, TrackInteractionEvent, TrackContextMenuEvent, WindowFunction, WigFeature, BedFeature, WigRenderConfig, AnnotationRenderConfig, RulerRenderConfig, SequenceRenderConfig, InteractionRenderConfig, TextFileFormat, SequenceProvider, Genome, ROI, ROISetConfig, ROIInteractionEvent } from './types';
24
+ import type { Locus, Track, DataSource, FeatureCacheEntry, SessionConfig, TrackSessionConfig, DataSourceConfig, TrackInteractionEvent, TrackContextMenuEvent, WigFeature, BedFeature, SequenceProvider, Genome, ROI, ROISetConfig, ROIInteractionEvent } from './types';
20
25
  import { ROISet } from './roi/roiSet';
21
26
  import type { CanvasProvider } from './canvasProvider';
22
27
  import type { WorkerProvider } from './workerProvider';
@@ -27,13 +32,17 @@ import type { RenderTheme } from './themes/renderTheme';
27
32
  import { EventEmitter } from './events';
28
33
  import type { ChromSizes, CumulativeOffsets } from './genome/chromSizes';
29
34
  import { type CreateTrackFromSessionOptions } from './session';
30
- import { RulerTrackCanvas } from './tracks/ruler/rulerTrackCanvas';
31
- import { WigTrackCanvas } from './tracks/wig/wigTrackCanvas';
32
- import { AnnotationTrackCanvas } from './tracks/annotation/annotationTrackCanvas';
33
35
  import { SequenceTrackCanvas } from './tracks/sequence/sequenceTrackCanvas';
34
- import { InteractionTrackCanvas } from './tracks/interaction/interactionTrackCanvas';
35
36
  import { StateProjection } from './stateProjection';
36
37
  import type { TrackSelector } from './trackSelector';
38
+ import type { UndoEntry, UndoEntryType } from './undoManager';
39
+ import { ROIManager } from './roiManager';
40
+ import { TrackDataManager } from './trackDataManager';
41
+ export type { AddRulerOptions, AddWigTrackOptions, AddGtxTrackOptions, AddSequenceTrackOptions, AddBedTrackOptions, AddInteractionTrackOptions, AddAnnotationTrackOptions, AddWigTrackWithFeaturesOptions, AddBedTrackWithFeaturesOptions, } from './trackFactories';
42
+ import type { RulerTrackCanvas } from './tracks/ruler/rulerTrackCanvas';
43
+ import type { WigTrackCanvas } from './tracks/wig/wigTrackCanvas';
44
+ import type { AnnotationTrackCanvas } from './tracks/annotation/annotationTrackCanvas';
45
+ import type { InteractionTrackCanvas } from './tracks/interaction/interactionTrackCanvas';
37
46
  export declare const BrowserEvent: {
38
47
  readonly LocusChange: "locuschange";
39
48
  readonly TrackAdded: "trackadded";
@@ -51,6 +60,10 @@ export declare const BrowserEvent: {
51
60
  readonly ROIClick: "roiclick";
52
61
  readonly ROIContextMenu: "roicontextmenu";
53
62
  readonly ThemeChanged: "themechange";
63
+ readonly TrackConfigChanged: "trackconfigchanged";
64
+ readonly Undo: "undo";
65
+ readonly Redo: "redo";
66
+ readonly UndoStackChanged: "undostackchanged";
54
67
  };
55
68
  export interface BrowserEvents {
56
69
  [BrowserEvent.LocusChange]: {
@@ -97,6 +110,19 @@ export interface BrowserEvents {
97
110
  [BrowserEvent.ThemeChanged]: {
98
111
  theme: RenderTheme;
99
112
  };
113
+ [BrowserEvent.TrackConfigChanged]: {
114
+ track: Track;
115
+ };
116
+ [BrowserEvent.Undo]: {
117
+ entry: UndoEntry;
118
+ };
119
+ [BrowserEvent.Redo]: {
120
+ entry: UndoEntry;
121
+ };
122
+ [BrowserEvent.UndoStackChanged]: {
123
+ canUndo: boolean;
124
+ canRedo: boolean;
125
+ };
100
126
  }
101
127
  /** Internal bookkeeping for a track + optional data source. */
102
128
  export interface ManagedTrack {
@@ -141,136 +167,10 @@ export interface HeadlessGenomeBrowserOptions {
141
167
  /** Custom StateProjection subclass instance. Default: lazily created StateProjection. */
142
168
  stateProjection?: StateProjection;
143
169
  }
144
- export interface AddRulerOptions {
145
- config?: Partial<RulerRenderConfig>;
146
- /** Max visible height — enables scrollable container in DOM browser. */
147
- maxTrackHeight?: number;
148
- }
149
- export interface AddWigTrackOptions {
150
- config?: Partial<WigRenderConfig>;
151
- /** Fixed pixel height (overrides config.height). */
152
- height?: number;
153
- /** Background color. */
154
- background?: string;
155
- /** Window function for BigWig summarization. Default: 'mean'. */
156
- windowFunction?: WindowFunction;
157
- /** Max visible height — enables scrollable container in DOM browser. */
158
- maxTrackHeight?: number;
159
- /** Track name for axis label. */
160
- name?: string;
161
- /** Arbitrary key-value metadata (e.g., assay, biosample, tissue). */
162
- metadata?: Record<string, string>;
163
- }
164
- export interface AddGtxTrackOptions {
165
- /** Experiment ID within the GTX file. */
166
- experimentId: string;
167
- config?: Partial<WigRenderConfig>;
168
- /** Fixed pixel height (overrides config.height). */
169
- height?: number;
170
- /** Background color. */
171
- background?: string;
172
- /** Window function for summarization. Default: 'mean'. */
173
- windowFunction?: WindowFunction;
174
- /** Max visible height — enables scrollable container in DOM browser. */
175
- maxTrackHeight?: number;
176
- /** Track name for axis label. */
177
- name?: string;
178
- /** Arbitrary key-value metadata (e.g., assay, biosample, tissue). */
179
- metadata?: Record<string, string>;
180
- }
181
- export interface AddSequenceTrackOptions {
182
- config?: Partial<SequenceRenderConfig>;
183
- /** Max visible height — enables scrollable container in DOM browser. */
184
- maxTrackHeight?: number;
185
- }
186
- export interface AddBedTrackOptions {
187
- config?: Partial<AnnotationRenderConfig>;
188
- /** Fixed pixel height. */
189
- height?: number;
190
- /** Background color. */
191
- background?: string;
192
- /** Explicit format override. When absent, inferred from URL. */
193
- format?: TextFileFormat;
194
- /** Index URL override for tabix-indexed files. */
195
- indexURL?: string;
196
- /** Whether the file is tabix-indexed. Auto-detected if absent. */
197
- indexed?: boolean;
198
- /** Max visible height — enables scrollable container in DOM browser. */
199
- maxTrackHeight?: number;
200
- /** Track name for axis label. */
201
- name?: string;
202
- /** Arbitrary key-value metadata (e.g., assay, biosample, tissue). */
203
- metadata?: Record<string, string>;
204
- }
205
- export interface AddInteractionTrackOptions {
206
- config?: Partial<InteractionRenderConfig>;
207
- /** Background color. */
208
- background?: string;
209
- /** Explicit format override (e.g., 'bedpe', 'interact'). Inferred from URL if absent. */
210
- format?: TextFileFormat;
211
- /** Index URL override for tabix-indexed files. */
212
- indexURL?: string;
213
- /** Whether the file is tabix-indexed. Auto-detected if absent. */
214
- indexed?: boolean;
215
- /** Track name for axis label. */
216
- name?: string;
217
- /** Arbitrary key-value metadata (e.g., assay, biosample, tissue). */
218
- metadata?: Record<string, string>;
219
- }
220
- export interface AddAnnotationTrackOptions {
221
- config?: Partial<AnnotationRenderConfig>;
222
- /** Fixed pixel height. */
223
- height?: number;
224
- /** Background color. */
225
- background?: string;
226
- /** Genome assembly for UCSC API. Default: 'hg38'. */
227
- genome?: string;
228
- /** UCSC track name. Default: 'ncbiRefSeq'. */
229
- track?: string;
230
- /** Max visible height — enables scrollable container in DOM browser. */
231
- maxTrackHeight?: number;
232
- /** Track name for axis label. Default: 'Genes'. */
233
- name?: string;
234
- /** Arbitrary key-value metadata (e.g., assay, biosample, tissue). */
235
- metadata?: Record<string, string>;
236
- }
237
- export interface AddWigTrackWithFeaturesOptions {
238
- config?: Partial<WigRenderConfig>;
239
- /** Fixed pixel height (overrides config.height). */
240
- height?: number;
241
- /** Background color. */
242
- background?: string;
243
- /** Max visible height — enables scrollable container in DOM browser. */
244
- maxTrackHeight?: number;
245
- /** Track name for axis label. */
246
- name?: string;
247
- /** Arbitrary key-value metadata (e.g., assay, biosample, tissue). */
248
- metadata?: Record<string, string>;
249
- }
250
- export interface AddBedTrackWithFeaturesOptions {
251
- config?: Partial<AnnotationRenderConfig>;
252
- /** Fixed pixel height. */
253
- height?: number;
254
- /** Background color. */
255
- background?: string;
256
- /** Max visible height — enables scrollable container in DOM browser. */
257
- maxTrackHeight?: number;
258
- /** Track name for axis label. */
259
- name?: string;
260
- /** Arbitrary key-value metadata (e.g., assay, biosample, tissue). */
261
- metadata?: Record<string, string>;
262
- }
263
170
  export declare class HeadlessGenomeBrowser {
264
171
  protected _locus: Locus;
265
172
  protected _viewportWidth: number;
266
173
  protected managedTracks: ManagedTrack[];
267
- protected roiSets: ROISet[];
268
- /** Inflight fetch promises keyed by (cacheKey + fetchRegion + bpPerPixel) for deduplication. */
269
- private inflightFetches;
270
- /** Timer for debouncing data loads during rapid zoom/pan. */
271
- private loadDebounceTimer;
272
- /** Set to true by dispose() to suppress post-dispose promise handlers. */
273
- private _disposed;
274
174
  /** When true, sortTracks() is a no-op. Used for batch track additions (e.g. loadSession). */
275
175
  private _deferSort;
276
176
  /** Canvas provider for environment abstraction. Available for convenience API / future use. */
@@ -298,23 +198,46 @@ export declare class HeadlessGenomeBrowser {
298
198
  readonly sequenceProvider?: SequenceProvider;
299
199
  readonly events: EventEmitter<BrowserEvents>;
300
200
  private _state?;
201
+ private readonly _undoManager;
202
+ /** ROI management — owns all ROI sets and operations. */
203
+ protected readonly roiManager: ROIManager;
204
+ /** Data lifecycle — owns fetch dedup, caching, abort, debounce. */
205
+ protected readonly dataManager: TrackDataManager;
301
206
  get theme(): RenderTheme;
302
207
  get locus(): Locus;
303
208
  get viewportWidth(): number;
209
+ /** Whether undo is available. Accepts optional skip predicate for filtering entry types. */
210
+ canUndo(skip?: (e: UndoEntry) => boolean): boolean;
211
+ /** Whether redo is available. Accepts optional skip predicate for filtering entry types. */
212
+ canRedo(skip?: (e: UndoEntry) => boolean): boolean;
304
213
  /** Agent-friendly state projection manager. Lazily created on first access. */
305
214
  get state(): StateProjection;
306
215
  constructor(options: HeadlessGenomeBrowserOptions);
307
- /**
308
- * Create a WorkerDataSource proxy for worker-eligible configs, or return null
309
- * if dataSourceWorkerProvider is not set. Handles create + chrom alias + offsets wiring.
310
- */
311
- private createWorkerDataSource;
216
+ /** Build the factory context from current browser state. */
217
+ private factoryContext;
312
218
  /** Clamp a locus to valid chromosome bounds. No-op if chromSizes is not set. */
313
219
  protected clamp(locus: Locus): Locus;
314
220
  /** Subscribe to a browser event. Returns an unsubscribe function. */
315
221
  on<K extends keyof BrowserEvents>(event: K, handler: (data: BrowserEvents[K]) => void): () => void;
316
222
  /** Unsubscribe from a browser event. */
317
223
  off<K extends keyof BrowserEvents>(event: K, handler?: (data: BrowserEvents[K]) => void): void;
224
+ /**
225
+ * Snapshot the current state before a mutation.
226
+ * No-op while paused (e.g., during loadSession restoration from undo/redo).
227
+ */
228
+ protected _snapshotForUndo(type: UndoEntryType): void;
229
+ /**
230
+ * Undo the last mutation. Restores the previous session state.
231
+ * Optionally skip entries matching a predicate (e.g., skip navigation-only entries).
232
+ */
233
+ undo(skip?: (e: UndoEntry) => boolean): boolean;
234
+ /**
235
+ * Redo the last undone mutation.
236
+ * Optionally skip entries matching a predicate.
237
+ */
238
+ redo(skip?: (e: UndoEntry) => boolean): boolean;
239
+ /** Clear all undo/redo history. */
240
+ clearUndoHistory(): void;
318
241
  /**
319
242
  * Update the viewport width and re-render.
320
243
  * In headless mode, call this when the logical viewport size changes.
@@ -332,16 +255,13 @@ export declare class HeadlessGenomeBrowser {
332
255
  moveTrack(track: Track, toIndex: number): void;
333
256
  /**
334
257
  * Sort tracks by priority (descending): positive = top, 0 = middle, negative = bottom.
335
- * Priority comes from the track type default + per-track `order` override.
336
- * Within the same effective priority, insertion order is preserved (stable sort).
337
258
  */
338
259
  private sortTracks;
339
260
  /** Hook for subclasses to react to track order changes (e.g., DOM reorder). */
340
261
  protected onTracksSorted(): void;
341
262
  /**
342
263
  * Persist current array positions into mt.order so future sorts preserve
343
- * manual reordering. Uses descending values (top track = highest) scaled
344
- * above the type-priority range so explicit order dominates.
264
+ * manual reordering.
345
265
  */
346
266
  protected _assignOrderFromPosition(): void;
347
267
  /** Find the ManagedTrack entry for a given track canvas. */
@@ -354,41 +274,24 @@ export declare class HeadlessGenomeBrowser {
354
274
  getTrack(id: string): Track | undefined;
355
275
  /** Get all managed tracks (read-only snapshot). */
356
276
  getManagedTracks(): readonly ManagedTrack[];
357
- /**
358
- * Find all managed tracks matching a selector.
359
- *
360
- * ```ts
361
- * browser.findTracks({ type: 'wig', where: { biosample: 'K562' } })
362
- * browser.findTracks({ name: 'H3K27ac' })
363
- * ```
364
- */
277
+ /** Find all managed tracks matching a selector. */
365
278
  findTracks(selector: TrackSelector): ManagedTrack[];
366
- /**
367
- * Remove all tracks matching a selector. Returns the number of tracks removed.
368
- *
369
- * ```ts
370
- * browser.removeTracks({ where: { assay: 'ATAC-seq' } }) // remove all ATAC-seq tracks
371
- * browser.removeTracks({ type: 'wig' }) // remove all wig tracks
372
- * ```
373
- */
279
+ /** Remove all tracks matching a selector. Returns the number of tracks removed. */
374
280
  removeTracks(selector: TrackSelector): number;
375
- /**
376
- * Merge metadata into all tracks matching a selector. Returns the number of tracks updated.
377
- * New keys are added; existing keys are overwritten.
378
- *
379
- * ```ts
380
- * browser.updateTrackMetadata({ type: 'wig' }, { project: 'ENCODE' })
381
- * ```
382
- */
281
+ /** Merge metadata into all tracks matching a selector. Returns the number of tracks updated. */
383
282
  updateTrackMetadata(selector: TrackSelector, metadata: Record<string, string>): number;
384
283
  /** Update the locus and re-render all tracks. Clamped to chromosome bounds. */
385
284
  setLocus(locus: Locus): void;
386
285
  /**
387
- * Parse a locus string and navigate to it.
388
- * e.g., "chr17:7,668,000-7,688,000"
389
- * Returns true if navigation succeeded.
286
+ * Parse a locus string or gene name and navigate to it.
287
+ *
288
+ * Search order (matches igv.js js/search.ts):
289
+ * 1. Coordinate string: "chr17:7,668,000-7,688,000"
290
+ * 2. Whole genome: "all" / "*"
291
+ * 3. Bare chromosome name: "chr17", "chrX"
292
+ * 4. Gene/feature name via web service: "BRCA1", "TP53"
390
293
  */
391
- search(query: string): boolean;
294
+ search(query: string): Promise<boolean>;
392
295
  /** Zoom in by a factor (default 2x) around the center. */
393
296
  zoomIn(factor?: number): void;
394
297
  /** Zoom out by a factor (default 2x) around the center. */
@@ -411,10 +314,7 @@ export declare class HeadlessGenomeBrowser {
411
314
  getCachedFeatures<F>(track: Track): F[] | undefined;
412
315
  /** Re-render all tracks at current locus. */
413
316
  render(): void;
414
- /**
415
- * Add a single ROI to a named set. Creates a user-defined set if it doesn't exist.
416
- * Returns the ROI (with generated ID if none provided).
417
- */
317
+ /** Add a single ROI to a named set. Creates a user-defined set if it doesn't exist. */
418
318
  addROI(roi: ROI, setName?: string): ROI;
419
319
  /** Add a full ROI set from config. Returns the created ROISet. */
420
320
  addROISet(config: ROISetConfig): ROISet;
@@ -436,15 +336,6 @@ export declare class HeadlessGenomeBrowser {
436
336
  getVisibleROIs(): ROI[];
437
337
  /**
438
338
  * Export the current view as an SVG string.
439
- *
440
- * Creates a Canvas2SVG context, renders each track with clipped groups and
441
- * vertical offsets, and returns the serialized SVG. Named entities are
442
- * replaced with numeric equivalents for standalone SVG compatibility.
443
- *
444
- * Mirrors igv.js Browser.toSVG() (js/browser.ts lines 352-388).
445
- *
446
- * @param options.width — Override viewport width (defaults to current viewportWidth).
447
- * @param options.backdropColor — Background color (defaults to 'white').
448
339
  */
449
340
  toSVG(options?: {
450
341
  width?: number;
@@ -452,54 +343,41 @@ export declare class HeadlessGenomeBrowser {
452
343
  }): string;
453
344
  /**
454
345
  * Serialize browser state to a SessionConfig.
455
- * Track configs are serialized via per-type serializers that drop
456
- * non-serializable values (functions, Promises) and only include
457
- * fields that differ from theme defaults.
458
346
  */
459
347
  toJSON(): SessionConfig;
460
348
  /**
461
349
  * Load a session, replacing all current tracks.
462
350
  * Disposes existing state, sets locus, and recreates tracks + data sources.
463
- *
464
- * Tracks are created headlessly (not attached to the DOM). Subclasses like
465
- * GenomeBrowser can override this to also attach track canvases to the DOM.
466
351
  */
467
352
  loadSession(session: SessionConfig, options?: CreateTrackFromSessionOptions): void;
468
353
  /**
469
354
  * Create a new HeadlessGenomeBrowser from a session config.
470
- * Creates the browser and loads all tracks from the session.
471
355
  */
472
356
  static fromSession(session: SessionConfig, options?: HeadlessGenomeBrowserOptions & CreateTrackFromSessionOptions): HeadlessGenomeBrowser;
473
357
  /**
474
358
  * Add a track from a session config using the track registry.
475
- *
476
- * Mirrors igv.js `Browser.createTrack(config)` (js/browser.ts lines 1074-1151)
477
- * which resolves type aliases via `getTrack()` and instantiates through the
478
- * track factory. Our version delegates to `createTrackFromConfig()` in the
479
- * registry, then registers the created track with this browser's data lifecycle.
480
- *
481
- * This is the generic entry point — the convenience methods below
482
- * (addRuler, addWigTrack, addGeneTrack) are sugar for common cases.
483
359
  */
484
360
  addTrackFromConfig(trackConfig: TrackSessionConfig): Track;
361
+ /** Register a factory result: addTrack + wire metadata + post-registration callback. */
362
+ private registerFactory;
485
363
  /** Add a ruler track. */
486
- addRuler(options?: AddRulerOptions): RulerTrackCanvas;
364
+ addRuler(options?: import('./trackFactories').AddRulerOptions): RulerTrackCanvas;
487
365
  /** Add a BigWig signal track. */
488
- addWigTrack(url: string, options?: AddWigTrackOptions): WigTrackCanvas;
366
+ addWigTrack(url: string, options?: import('./trackFactories').AddWigTrackOptions): WigTrackCanvas;
489
367
  /** Add a GTX signal track (single experiment from a multi-experiment GTX file). */
490
- addGtxTrack(url: string, options: AddGtxTrackOptions): WigTrackCanvas;
368
+ addGtxTrack(url: string, options: import('./trackFactories').AddGtxTrackOptions): WigTrackCanvas;
491
369
  /** Add a UCSC gene annotation track. */
492
- addGeneTrack(options?: AddAnnotationTrackOptions): AnnotationTrackCanvas;
493
- /** Add a BED/peak annotation track from a URL. Supports plain text and tabix-indexed files. */
494
- addBedTrack(url: string, options?: AddBedTrackOptions): AnnotationTrackCanvas;
370
+ addGeneTrack(options?: import('./trackFactories').AddAnnotationTrackOptions): AnnotationTrackCanvas;
371
+ /** Add a BED/peak annotation track from a URL. */
372
+ addBedTrack(url: string, options?: import('./trackFactories').AddBedTrackOptions): AnnotationTrackCanvas;
495
373
  /** Add an interaction (arc/BEDPE) track from a URL. */
496
- addInteractionTrack(url: string, options?: AddInteractionTrackOptions): InteractionTrackCanvas;
374
+ addInteractionTrack(url: string, options?: import('./trackFactories').AddInteractionTrackOptions): InteractionTrackCanvas;
497
375
  /** Add a BigWig-style signal track backed by in-memory features (no URL required). */
498
- addWigTrackWithFeatures(features: WigFeature[], options?: AddWigTrackWithFeaturesOptions): WigTrackCanvas;
499
- /** Add a BED/annotation track backed by in-memory features (no URL required). Features must include `chr`. */
500
- addBedTrackWithFeatures(features: BedFeature[], options?: AddBedTrackWithFeaturesOptions): AnnotationTrackCanvas;
501
- /** Add a DNA/RNA sequence track. Data fetching is handled automatically via the genome's sequence provider. */
502
- addSequenceTrack(options?: AddSequenceTrackOptions): SequenceTrackCanvas;
376
+ addWigTrackWithFeatures(features: WigFeature[], options?: import('./trackFactories').AddWigTrackWithFeaturesOptions): WigTrackCanvas;
377
+ /** Add a BED/annotation track backed by in-memory features (no URL required). */
378
+ addBedTrackWithFeatures(features: BedFeature[], options?: import('./trackFactories').AddBedTrackWithFeaturesOptions): AnnotationTrackCanvas;
379
+ /** Add a DNA/RNA sequence track. */
380
+ addSequenceTrack(options?: import('./trackFactories').AddSequenceTrackOptions): SequenceTrackCanvas;
503
381
  /** Apply a new render theme to the browser and all existing tracks. */
504
382
  setTheme(theme: Partial<RenderTheme>): void;
505
383
  /** Clean up event listeners, abort in-flight requests, clear tracks and ROIs. */
@@ -507,22 +385,7 @@ export declare class HeadlessGenomeBrowser {
507
385
  /**
508
386
  * Resolve pixel coordinates on a track canvas to interaction data.
509
387
  * Used by GenomeBrowser to build event payloads from pointer events.
510
- * Returns null if the track has no features at the given point.
511
388
  */
512
389
  protected resolveInteraction(track: Track, x: number, y: number): TrackInteractionEvent | null;
513
- /**
514
- * Debounced wrapper around loadAllTracksIfNeeded.
515
- * During rapid zoom/pan, this coalesces multiple setLocus() calls into a
516
- * single data fetch cycle after the interaction settles (100ms quiet period).
517
- * Abort in-flight requests immediately so they don't race with the eventual fetch.
518
- */
519
- private debouncedLoad;
520
390
  protected loadAllTracksIfNeeded(): void;
521
- /**
522
- * Load data for a single track, deduplicating against inflight fetches
523
- * from other tracks with the same data source identity.
524
- *
525
- * Works for both initial addTrack() loads and bulk loadAllTracksIfNeeded() calls.
526
- */
527
- private loadTrackWithDedup;
528
391
  }