@jbrowse/core 5.0.0-beta.10 → 5.0.0-beta.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 (67) hide show
  1. package/README.md +113 -5
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.js +0 -2
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.js +22 -6
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.js +3 -4
  5. package/esm/BaseFeatureWidget/SequenceFeatureDetails/useSequenceData.js +8 -5
  6. package/esm/CorePlugin.js +32 -1
  7. package/esm/ReExports/coreModules.generated.js +248 -246
  8. package/esm/ReExports/coreWorkerModules.generated.js +246 -244
  9. package/esm/ReExports/list.js +3 -2
  10. package/esm/configuration/index.d.ts +2 -0
  11. package/esm/configuration/index.js +1 -0
  12. package/esm/configuration/plot.d.ts +61 -0
  13. package/esm/configuration/plot.js +142 -0
  14. package/esm/pluggableElementTypes/DisplayType.d.ts +7 -0
  15. package/esm/pluggableElementTypes/DisplayType.js +6 -0
  16. package/esm/pluggableElementTypes/WidgetType.d.ts +6 -0
  17. package/esm/pluggableElementTypes/WidgetType.js +6 -0
  18. package/esm/pluggableElementTypes/index.js +1 -8
  19. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +57 -1
  20. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +84 -2
  21. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +2 -2
  22. package/esm/pluggableElementTypes/models/BaseViewModel.js +1 -1
  23. package/esm/ui/JexlFilterDialog.d.ts +1 -1
  24. package/esm/ui/JexlFilterDialog.js +2 -3
  25. package/esm/util/TimeTraveller.d.ts +3 -0
  26. package/esm/util/TimeTraveller.js +34 -2
  27. package/esm/util/baseDisplayConfig.d.ts +8 -0
  28. package/esm/util/baseDisplayConfig.js +27 -0
  29. package/esm/util/cachedSetup.d.ts +16 -6
  30. package/esm/util/cachedSetup.js +108 -38
  31. package/esm/util/cellMatches.d.ts +23 -0
  32. package/esm/util/cellMatches.js +264 -0
  33. package/esm/util/cellsStep.d.ts +29 -0
  34. package/esm/util/cellsStep.js +437 -0
  35. package/esm/util/copyToClipboard.js +8 -1
  36. package/esm/util/createAbortRotation.js +3 -3
  37. package/esm/util/featureTransforms.d.ts +7 -6
  38. package/esm/util/featureTransforms.js +131 -479
  39. package/esm/util/fetchPhases.d.ts +1 -1
  40. package/esm/util/formatBytes.js +1 -1
  41. package/esm/util/formatGuessers.d.ts +25 -14
  42. package/esm/util/formatGuessers.js +42 -27
  43. package/esm/util/formatRelativeTime.js +1 -1
  44. package/esm/util/getLocationUri.d.ts +2 -1
  45. package/esm/util/getLocationUri.js +8 -2
  46. package/esm/util/groupKeys.d.ts +4 -5
  47. package/esm/util/groupKeys.js +7 -6
  48. package/esm/util/intervals.js +9 -4
  49. package/esm/util/io/index.js +3 -1
  50. package/esm/util/jexlFilters.d.ts +31 -49
  51. package/esm/util/jexlFilters.js +29 -39
  52. package/esm/util/locString.js +5 -2
  53. package/esm/util/markEncoding.js +48 -8
  54. package/esm/util/markEncodingTypes.d.ts +8 -1
  55. package/esm/util/springAnimate.js +1 -1
  56. package/esm/util/stepTables.d.ts +14 -0
  57. package/esm/util/stepTables.js +38 -4
  58. package/esm/util/tabix.d.ts +6 -2
  59. package/esm/util/tabix.js +2 -2
  60. package/esm/util/tracks.d.ts +3 -30
  61. package/esm/util/tracks.js +4 -39
  62. package/esm/util/unknownSnapshotKeys.d.ts +3 -1
  63. package/esm/util/unknownSnapshotKeys.js +5 -11
  64. package/esm/util/usePanZoom.js +10 -3
  65. package/esm/util/useRafCommit.js +1 -0
  66. package/esm/util/withFeatureDetails.js +4 -0
  67. package/package.json +9 -8
@@ -61,7 +61,7 @@ export function springAnimate({ from, to, write, read, onFinish = () => { }, pre
61
61
  animationFrameId = requestAnimationFrame(() => {
62
62
  update({
63
63
  lastPosition: position,
64
- lastTime: time,
64
+ lastTime: lastTime + numSteps,
65
65
  lastVelocity: velocity,
66
66
  });
67
67
  });
@@ -1,3 +1,4 @@
1
+ import { DerivedTable } from './featureTable.ts';
1
2
  import type { Column, FeatureTable, MadeRows } from './featureTable.ts';
2
3
  import type { AggregateOp, AggregateStep, BinStep } from './markEncodingTypes.ts';
3
4
  import type { Feature, SimpleFeatureSerialized } from './simpleFeature.ts';
@@ -15,6 +16,19 @@ export interface Staged {
15
16
  table: FeatureTable;
16
17
  bounds: Bounds;
17
18
  }
19
+ export declare function boundsThrough(bounds: Bounds, parentRow: Uint32Array): Bounds;
20
+ /**
21
+ * The entries a `flatten` fanned out, one row each over the container row it
22
+ * came from. A container kept with nothing to fan out is a row of its own
23
+ * that reads everything off itself.
24
+ */
25
+ export declare abstract class FannedTable extends DerivedTable {
26
+ get madeFrom(): boolean;
27
+ /** A container kept with nothing to fan out: the row is the container. */
28
+ abstract isKept(i: number): boolean;
29
+ abstract get hasKept(): boolean;
30
+ row(i: number): Feature;
31
+ }
18
32
  export declare function stepReader(table: FeatureTable, ref: string, step: string): (i: number) => unknown;
19
33
  export declare function stepNumberReader(table: FeatureTable, ref: string, step: string): (i: number) => number;
20
34
  export declare function groupKey(value: unknown): unknown;
@@ -1,14 +1,48 @@
1
- // The pieces of the transform steps that the fused bin-and-aggregate kernel
2
- // shares with the steps themselves. Imported by relative path only, so none
3
- // of it is a package subpath or part of the plugin ABI.
1
+ // The pieces of the transform steps that the fused kernels share with the
2
+ // steps themselves. Imported by relative path only, so none of it is a
3
+ // package subpath or part of the plugin ABI.
4
4
  import { aggregateFieldName } from './aggregateFieldName.js';
5
- import { NO_COLUMN, TableRow, numberReaderOf, readerOf, valueAt, } from './featureTable.js';
5
+ import { DerivedTable, NO_COLUMN, TableRow, numberReaderOf, readerOf, valueAt, } from './featureTable.js';
6
6
  import { fieldReader, isPlainFieldRef } from './fieldReader.js';
7
7
  import { isJexl } from './jexlStrings.js';
8
8
  import { numericValue } from './numericValue.js';
9
9
  export const DEFAULT_BIN_AS = ['start', 'end'];
10
10
  /** What a `bin` over `fields` writes on each piece: the bases of its interval inside its bin. */
11
11
  export const BIN_OVERLAP_FIELD = 'overlap';
12
+ // Section starts through a step whose rows came from its input's in order:
13
+ // each section starts at the first row whose parent row is in it.
14
+ export function boundsThrough(bounds, parentRow) {
15
+ const out = new Uint32Array(bounds.length);
16
+ let lo = 0;
17
+ for (let s = 0; s < bounds.length; s++) {
18
+ const edge = bounds[s];
19
+ let hi = parentRow.length;
20
+ while (lo < hi) {
21
+ const mid = (lo + hi) >>> 1;
22
+ if (parentRow[mid] < edge) {
23
+ lo = mid + 1;
24
+ }
25
+ else {
26
+ hi = mid;
27
+ }
28
+ }
29
+ out[s] = lo;
30
+ }
31
+ return out;
32
+ }
33
+ /**
34
+ * The entries a `flatten` fanned out, one row each over the container row it
35
+ * came from. A container kept with nothing to fan out is a row of its own
36
+ * that reads everything off itself.
37
+ */
38
+ export class FannedTable extends DerivedTable {
39
+ get madeFrom() {
40
+ return true;
41
+ }
42
+ row(i) {
43
+ return this.isKept(i) ? this.parent.row(this.parentOf(i)) : super.row(i);
44
+ }
45
+ }
12
46
  // A step reads a name or a dotted path. A plain name reads the table's column;
13
47
  // a path walks each row, chosen once per step. A computed field is a `formula`
14
48
  // step's to make.
@@ -90,7 +90,9 @@ export declare function readTabixLinesRedispatched(file: TabixLineSource, query:
90
90
  * structural for the same reason as {@link TabixLineSource}.
91
91
  */
92
92
  interface TabixHeaderSource {
93
- getHeaderLines(): Promise<string[]>;
93
+ getHeaderLines(opts?: {
94
+ signal?: AbortSignal;
95
+ }): Promise<string[]>;
94
96
  }
95
97
  /**
96
98
  * The header lines of a tabix-indexed file, however that file kept them.
@@ -121,5 +123,7 @@ interface TabixHeaderSource {
121
123
  * commented block and then the counted rows used to fetch and decompress the
122
124
  * same bytes twice, which every bare-header file did on every call.
123
125
  */
124
- export declare function readTabixHeaderLines(file: TabixHeaderSource): Promise<string[]>;
126
+ export declare function readTabixHeaderLines(file: TabixHeaderSource, opts?: {
127
+ signal?: AbortSignal;
128
+ }): Promise<string[]>;
125
129
  export {};
package/esm/util/tabix.js CHANGED
@@ -143,6 +143,6 @@ function mergeTabixLines(...groups) {
143
143
  * commented block and then the counted rows used to fetch and decompress the
144
144
  * same bytes twice, which every bare-header file did on every call.
145
145
  */
146
- export function readTabixHeaderLines(file) {
147
- return file.getHeaderLines();
146
+ export function readTabixHeaderLines(file, opts) {
147
+ return file.getHeaderLines(opts);
148
148
  }
@@ -1,5 +1,8 @@
1
1
  export { getFileName } from './getFileName.ts';
2
2
  export { getRpcSessionId } from './parentWalk.ts';
3
+ export { makeIndex } from './formatGuessers.ts';
4
+ export { isLooseTrackConfig, type LooseTrackInput, } from '@jbrowse/add-track-core';
5
+ import { type LooseTrackInput } from '@jbrowse/add-track-core';
3
6
  import type PluginManager from '../PluginManager.ts';
4
7
  import type { AnyConfigurationModel } from '../configuration/index.ts';
5
8
  import type { BlobLocation, FileHandleLocation, FileLocation, PreFileLocation } from './types/data.ts';
@@ -132,23 +135,6 @@ export declare function restoreFileHandlesFromSnapshot(sessionSnapshot: unknown,
132
135
  success: false;
133
136
  error: unknown;
134
137
  })[]>;
135
- /**
136
- * creates a new location from the provided location including the appropriate
137
- * suffix and location type
138
- *
139
- * @param location - the FileLocation
140
- * @param suffix - the file suffix (e.g. .bam)
141
- * @returns the constructed location object from the provided parameters
142
- */
143
- export declare function makeIndex(location: FileLocation, suffix: string): BlobLocation | FileHandleLocation | {
144
- uri: string;
145
- locationType: string;
146
- baseUri?: string | undefined;
147
- localPath?: undefined;
148
- } | {
149
- localPath: string;
150
- locationType: string;
151
- };
152
138
  /**
153
139
  * constructs a potential index file (with suffix) from the provided file name
154
140
  *
@@ -227,12 +213,6 @@ export declare function addTrackTypeGuesser(pluginManager: PluginManager, guess:
227
213
  export declare function stripFileExtension(name: string): string;
228
214
  export declare function guessAdapter(file: FileLocation, index: FileLocation | undefined, adapterHint?: string, model?: IAnyStateTreeNode): AdapterConfig;
229
215
  export declare function guessTrackType(adapterType: string, model?: IAnyStateTreeNode, file?: FileLocation): string;
230
- export interface LooseTrackInput {
231
- uri: string;
232
- index?: string;
233
- baseUri?: string;
234
- [key: string]: unknown;
235
- }
236
216
  /**
237
217
  * Expand a loose track description — a bare data-file URI, or an object with
238
218
  * `uri` (and optional `index`) plus any extra config keys — into a full track
@@ -268,13 +248,6 @@ export declare function guessTrackConfForLocation(file: FileLocation, index: Fil
268
248
  assemblyNames: string[];
269
249
  adapter: AdapterConfig;
270
250
  };
271
- /**
272
- * Whether a track snapshot is the loose `{ uri, ... }` form — a data file with
273
- * no `adapter` — that {@link expandLooseTrackConfig} expands.
274
- */
275
- export declare function isLooseTrackConfig(snap: unknown): snap is LooseTrackInput & {
276
- trackId?: string;
277
- };
278
251
  /**
279
252
  * Expand a loose track config into a full one and leave any other snapshot
280
253
  * untouched, so it can sit on every path a track snapshot enters the tree by:
@@ -8,12 +8,16 @@ export { getFileName } from './getFileName.js';
8
8
  // it. `fetchContext.ts` takes it from mstUtils instead, which is what keeps the
9
9
  // configuration schemas this file pulls in out of the fetch harness's graph.
10
10
  export { getRpcSessionId } from './parentWalk.js';
11
+ export { makeIndex } from './formatGuessers.js';
12
+ export { isLooseTrackConfig, } from '@jbrowse/add-track-core';
13
+ import { isLooseTrackConfig, } from '@jbrowse/add-track-core';
11
14
  import { asModelType, getParent, getSnapshot, getType, hasParent, isAlive, isStateTreeNode, } from '@jbrowse/mobx-state-tree';
12
15
  import { observable, runInAction, untracked } from 'mobx';
13
16
  import { readConfObject } from '../configuration/index.js';
14
17
  import { adapterConfigCacheKey } from '../data_adapters/dataAdapterCache.js';
15
18
  import { displayCandidates, displayTypesFedBy, } from '../pluggableElementTypes/models/baseTrackConfig.js';
16
19
  import { getFileHandle, storeFileHandle, verifyPermission, } from './fileHandleStore.js';
20
+ import { makeIndex } from './formatGuessers.js';
17
21
  import { getFileName } from './getFileName.js';
18
22
  import { getContainingView, getEnv, getSession, objectHash, } from './mstUtils.js';
19
23
  import { isViewModel } from './types/index.js';
@@ -279,34 +283,6 @@ export function findFileHandleIds(obj) {
279
283
  export async function restoreFileHandlesFromSnapshot(sessionSnapshot, requestPermission = false) {
280
284
  return restoreFileHandles([...findFileHandleIds(sessionSnapshot)], requestPermission);
281
285
  }
282
- /**
283
- * creates a new location from the provided location including the appropriate
284
- * suffix and location type
285
- *
286
- * @param location - the FileLocation
287
- * @param suffix - the file suffix (e.g. .bam)
288
- * @returns the constructed location object from the provided parameters
289
- */
290
- export function makeIndex(location, suffix) {
291
- if ('uri' in location) {
292
- return {
293
- uri: location.uri + suffix,
294
- locationType: 'UriLocation',
295
- // carry the parent's baseUri so a derived sibling index resolves against
296
- // the same config location as the file it indexes
297
- ...(location.baseUri ? { baseUri: location.baseUri } : {}),
298
- };
299
- }
300
- else if ('localPath' in location) {
301
- return {
302
- localPath: location.localPath + suffix,
303
- locationType: 'LocalPathLocation',
304
- };
305
- }
306
- else {
307
- return location;
308
- }
309
- }
310
286
  /**
311
287
  * constructs a potential index file (with suffix) from the provided file name
312
288
  *
@@ -450,17 +426,6 @@ export function guessTrackConfForLocation(file, index, pluginManager, assemblyNa
450
426
  adapter,
451
427
  };
452
428
  }
453
- /**
454
- * Whether a track snapshot is the loose `{ uri, ... }` form — a data file with
455
- * no `adapter` — that {@link expandLooseTrackConfig} expands.
456
- */
457
- export function isLooseTrackConfig(snap) {
458
- return (typeof snap === 'object' &&
459
- snap !== null &&
460
- !Array.isArray(snap) &&
461
- typeof snap.uri === 'string' &&
462
- !('adapter' in snap));
463
- }
464
429
  /**
465
430
  * Expand a loose track config into a full one and leave any other snapshot
466
431
  * untouched, so it can sit on every path a track snapshot enters the tree by:
@@ -25,7 +25,9 @@ export declare function displaySetterName(key: string): string;
25
25
  export declare function setterOnlyMessage(label: string, keys: string[]): string;
26
26
  /**
27
27
  * Name the keys a view was handed and could not place, from the partition
28
- * `withLaunchInput` runs on the snapshot.
28
+ * `withLaunchInput` runs on the snapshot. The console alone, like
29
+ * `reportLegacyInit`: the view opened without them, and the keys are usually a
30
+ * v4 session's retired state that a visitor holding the link cannot act on.
29
31
  */
30
32
  export declare function reportUnknownKeys(self: IStateTreeNode, keys: string[]): void;
31
33
  /**
@@ -28,19 +28,13 @@ export function setterOnlyMessage(label, keys) {
28
28
  }
29
29
  /**
30
30
  * Name the keys a view was handed and could not place, from the partition
31
- * `withLaunchInput` runs on the snapshot.
31
+ * `withLaunchInput` runs on the snapshot. The console alone, like
32
+ * `reportLegacyInit`: the view opened without them, and the keys are usually a
33
+ * v4 session's retired state that a visitor holding the link cannot act on.
32
34
  */
33
35
  export function reportUnknownKeys(self, keys) {
34
- if (!keys.length) {
35
- return;
36
- }
37
- const message = unknownKeysMessage(viewLabel(self), keys);
38
- console.warn(message);
39
- try {
40
- getNotificationSink(self).notify(message, 'warning');
41
- }
42
- catch {
43
- // a view built outside a session has nowhere to put it
36
+ if (keys.length) {
37
+ console.warn(unknownKeysMessage(viewLabel(self), keys));
44
38
  }
45
39
  }
46
40
  /**
@@ -113,6 +113,9 @@ export function usePanZoom(ref, view, { touchAction = 'none', } = {}) {
113
113
  };
114
114
  }, [ref, touchAction]);
115
115
  function endDrag(event) {
116
+ if (dragRef.current?.pointerId !== event.pointerId) {
117
+ return;
118
+ }
116
119
  dragRef.current = undefined;
117
120
  // release only what the move handler took — a press that stayed under the
118
121
  // threshold never captured anything
@@ -131,7 +134,7 @@ export function usePanZoom(ref, view, { touchAction = 'none', } = {}) {
131
134
  // lands on an icon inside the control. Shift is left alone too: it is
132
135
  // what a range-select of the host's own would want, and it is what
133
136
  // JBrowse's own view uses it for.
134
- if (event.button !== 0 || event.shiftKey) {
137
+ if (!event.isPrimary || event.button !== 0 || event.shiftKey) {
135
138
  return;
136
139
  }
137
140
  if (event.target instanceof Element &&
@@ -139,11 +142,15 @@ export function usePanZoom(ref, view, { touchAction = 'none', } = {}) {
139
142
  return;
140
143
  }
141
144
  // Note what this does *not* do: capture the pointer. See onPointerMove.
142
- dragRef.current = { x: event.clientX, panning: false };
145
+ dragRef.current = {
146
+ x: event.clientX,
147
+ panning: false,
148
+ pointerId: event.pointerId,
149
+ };
143
150
  },
144
151
  onPointerMove(event) {
145
152
  const drag = dragRef.current;
146
- if (!drag) {
153
+ if (!drag || drag.pointerId !== event.pointerId) {
147
154
  return;
148
155
  }
149
156
  if (!drag.panning) {
@@ -18,6 +18,7 @@ export function useRafCommit(commit) {
18
18
  const pending = pendingRef.current;
19
19
  if (pending) {
20
20
  cancelAnimationFrame(pending.id);
21
+ pendingRef.current = undefined;
21
22
  }
22
23
  }, []);
23
24
  const schedule = useCallback((value) => {
@@ -1,4 +1,5 @@
1
1
  import { isAlive } from '@jbrowse/mobx-state-tree';
2
+ import { isAbortException } from './aborting.js';
2
3
  import { notifyFeatureDetailsMiss } from './openFeatureWidget.js';
3
4
  import { getNotificationSink } from './sessionServices.js';
4
5
  /**
@@ -48,6 +49,9 @@ export async function withFeatureDetails(self, fetch, onFeat, onMiss = () => {
48
49
  }
49
50
  }
50
51
  catch (e) {
52
+ if (isAbortException(e)) {
53
+ return;
54
+ }
51
55
  // Logged whatever happened, and only toasted while the display is still
52
56
  // there: `getSession` throws on a detached node, and a message naming a
53
57
  // track the user has already closed is noise they cannot act on.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/core",
3
- "version": "5.0.0-beta.10",
3
+ "version": "5.0.0-beta.11",
4
4
  "type": "module",
5
5
  "description": "JBrowse 2 core libraries used by plugins",
6
6
  "keywords": [
@@ -166,6 +166,7 @@
166
166
  "./util/assemblyConfigUtils": "./esm/util/assemblyConfigUtils.js",
167
167
  "./util/bandHeight": "./esm/util/bandHeight.js",
168
168
  "./util/bandLayout": "./esm/util/bandLayout.js",
169
+ "./util/baseDisplayConfig": "./esm/util/baseDisplayConfig.js",
169
170
  "./util/bgzfWorkerPool": "./esm/util/bgzfWorkerPool.js",
170
171
  "./util/blockTypes": "./esm/util/blockTypes.js",
171
172
  "./util/cacheBudgets": "./esm/util/cacheBudgets.js",
@@ -297,12 +298,12 @@
297
298
  "@emotion/utils": "^1.4.2",
298
299
  "@floating-ui/react": "^0.27.20",
299
300
  "@gmod/bgzf-filehandle": "^6.7.0",
300
- "@gmod/range-cache-filehandle": "^1.4.0",
301
+ "@gmod/range-cache-filehandle": "^1.5.0",
301
302
  "@gmod/shared-read-cache": "^1.7.2",
302
303
  "@gmod/vcf": "^7.2.0",
303
304
  "@jbrowse/jexl": "^6.0.0",
304
- "@jbrowse/mobx-state-tree": "^6.6.1",
305
- "@jbrowse/quick-lru": "^7.3.5",
305
+ "@jbrowse/mobx-state-tree": "^6.7.0",
306
+ "@jbrowse/quick-lru": "^8.0.0",
306
307
  "@leeoniya/ufuzzy": "^1.0.19",
307
308
  "@mui/icons-material": "^9.4.0",
308
309
  "@mui/material": "^9.4.0",
@@ -311,14 +312,14 @@
311
312
  "canvas-sequencer-ts": "^3.1.3",
312
313
  "compare-versions": "^6.1.1",
313
314
  "dompurify": "^3.4.16",
314
- "generic-filehandle2": "^2.4.0",
315
+ "generic-filehandle2": "^2.5.0",
315
316
  "idb": "^8.0.3",
316
317
  "mobx": "^7.0.5",
317
318
  "mobx-react": "^10.0.2",
318
319
  "rxjs": "^7.8.2",
319
- "source-map-js": "^1.2.1",
320
- "@jbrowse/add-track-core": "^5.0.0-beta.10",
321
- "@jbrowse/render-core": "^5.0.0-beta.10"
320
+ "source-map-js": "^1.2.2",
321
+ "@jbrowse/add-track-core": "^5.0.0-beta.11",
322
+ "@jbrowse/render-core": "^5.0.0-beta.11"
322
323
  },
323
324
  "peerDependencies": {
324
325
  "react": ">=19.0.0",