@jbrowse/core 2.3.4 → 2.4.0

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 (46) hide show
  1. package/BaseFeatureWidget/BaseFeatureDetail.d.ts +18 -19
  2. package/BaseFeatureWidget/BaseFeatureDetail.js +64 -61
  3. package/BaseFeatureWidget/SequenceBox.js +9 -3
  4. package/BaseFeatureWidget/SequenceFeatureDetails.js +70 -52
  5. package/BaseFeatureWidget/SequencePanel.d.ts +3 -3
  6. package/BaseFeatureWidget/SequencePanel.js +8 -5
  7. package/CorePlugin.js +2 -7
  8. package/PluginLoader.d.ts +1 -1
  9. package/PluginLoader.js +17 -21
  10. package/data_adapters/CytobandAdapter/CytobandAdapter.d.ts +8 -0
  11. package/data_adapters/CytobandAdapter/CytobandAdapter.js +40 -0
  12. package/data_adapters/CytobandAdapter/configSchema.d.ts +2 -0
  13. package/data_adapters/CytobandAdapter/configSchema.js +17 -0
  14. package/data_adapters/CytobandAdapter/index.d.ts +3 -0
  15. package/data_adapters/CytobandAdapter/index.js +37 -0
  16. package/package.json +5 -4
  17. package/pluggableElementTypes/PluggableElementBase.d.ts +1 -1
  18. package/pluggableElementTypes/PluggableElementBase.js +1 -2
  19. package/pluggableElementTypes/RpcMethodType.d.ts +5 -8
  20. package/pluggableElementTypes/RpcMethodType.js +22 -33
  21. package/pluggableElementTypes/renderers/CircularChordRendererType.d.ts +13 -2
  22. package/pluggableElementTypes/renderers/CircularChordRendererType.js +10 -2
  23. package/pluggableElementTypes/renderers/ComparativeServerSideRendererType.d.ts +6 -0
  24. package/pluggableElementTypes/renderers/ComparativeServerSideRendererType.js +9 -1
  25. package/pluggableElementTypes/renderers/ServerSideRendererType.js +2 -34
  26. package/tsconfig.build.tsbuildinfo +1 -1
  27. package/ui/App.js +3 -18
  28. package/ui/LoadingEllipses.js +6 -6
  29. package/ui/Menu.js +2 -2
  30. package/ui/ResizeBar.js +4 -5
  31. package/ui/SanitizedHTML.js +2 -0
  32. package/ui/ViewContainer.js +3 -38
  33. package/ui/ViewMenu.d.ts +9 -0
  34. package/ui/ViewMenu.js +69 -0
  35. package/ui/ViewPanel.d.ts +19 -0
  36. package/ui/ViewPanel.js +49 -0
  37. package/ui/theme.d.ts +10 -166
  38. package/ui/theme.js +260 -48
  39. package/util/index.d.ts +3 -2
  40. package/util/index.js +11 -5
  41. package/util/map-obj.d.ts +3 -0
  42. package/util/map-obj.js +33 -0
  43. package/util/offscreenCanvasUtils.d.ts +18 -4
  44. package/util/offscreenCanvasUtils.js +48 -7
  45. package/data_adapters/CytobandAdapter.d.ts +0 -8
  46. package/data_adapters/CytobandAdapter.js +0 -49
package/ui/theme.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createJBrowseTheme = exports.createJBrowseBaseTheme = exports.createJBrowseDefaultOverrides = exports.createJBrowseDefaultProps = exports.jbrowseDefaultPalette = void 0;
6
+ exports.createJBrowseTheme = exports.createJBrowseBaseTheme = exports.defaultThemes = void 0;
7
7
  const colors_1 = require("@mui/material/colors");
8
8
  const styles_1 = require("@mui/material/styles");
9
9
  const deepmerge_1 = __importDefault(require("deepmerge"));
@@ -12,28 +12,156 @@ const grape = '#721E63';
12
12
  const forest = '#135560';
13
13
  const mandarin = '#FFB11D';
14
14
  const refTheme = (0, styles_1.createTheme)();
15
- exports.jbrowseDefaultPalette = {
16
- // type: 'dark',
17
- primary: { main: midnight },
18
- secondary: { main: grape },
19
- tertiary: refTheme.palette.augmentColor({ color: { main: forest } }),
20
- quaternary: refTheme.palette.augmentColor({ color: { main: mandarin } }),
21
- stopCodon: '#e22',
22
- startCodon: '#3e3',
23
- bases: {
24
- A: refTheme.palette.augmentColor({ color: colors_1.green }),
25
- C: refTheme.palette.augmentColor({ color: colors_1.blue }),
26
- G: refTheme.palette.augmentColor({ color: colors_1.amber }),
27
- T: refTheme.palette.augmentColor({ color: colors_1.red }),
28
- },
15
+ function stockTheme() {
16
+ return {
17
+ palette: {
18
+ mode: undefined,
19
+ primary: { main: midnight },
20
+ secondary: { main: grape },
21
+ tertiary: refTheme.palette.augmentColor({ color: { main: forest } }),
22
+ quaternary: refTheme.palette.augmentColor({ color: { main: mandarin } }),
23
+ stopCodon: '#e22',
24
+ startCodon: '#3e3',
25
+ bases: {
26
+ A: refTheme.palette.augmentColor({ color: colors_1.green }),
27
+ C: refTheme.palette.augmentColor({ color: colors_1.blue }),
28
+ G: refTheme.palette.augmentColor({ color: colors_1.amber }),
29
+ T: refTheme.palette.augmentColor({ color: colors_1.red }),
30
+ },
31
+ },
32
+ components: {
33
+ MuiLink: {
34
+ styleOverrides: {
35
+ // the default link color uses theme.palette.primary.main which is
36
+ // very bad with dark mode+midnight primary
37
+ //
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ root: ({ theme }) => ({
40
+ color: theme.palette.tertiary.main,
41
+ }),
42
+ },
43
+ },
44
+ },
45
+ };
46
+ }
47
+ function getDefaultTheme() {
48
+ return {
49
+ name: 'Default (from config)',
50
+ ...stockTheme(),
51
+ };
52
+ }
53
+ function getLightStockTheme() {
54
+ return {
55
+ name: 'Light (stock)',
56
+ ...stockTheme(),
57
+ };
58
+ }
59
+ function getDarkStockTheme() {
60
+ return {
61
+ name: 'Dark (stock)',
62
+ palette: {
63
+ mode: 'dark',
64
+ primary: { main: midnight },
65
+ secondary: { main: grape },
66
+ tertiary: refTheme.palette.augmentColor({ color: { main: forest } }),
67
+ quaternary: refTheme.palette.augmentColor({ color: { main: mandarin } }),
68
+ stopCodon: '#e22',
69
+ startCodon: '#3e3',
70
+ bases: {
71
+ A: refTheme.palette.augmentColor({ color: colors_1.green }),
72
+ C: refTheme.palette.augmentColor({ color: colors_1.blue }),
73
+ G: refTheme.palette.augmentColor({ color: colors_1.amber }),
74
+ T: refTheme.palette.augmentColor({ color: colors_1.red }),
75
+ },
76
+ },
77
+ components: {
78
+ MuiAppBar: {
79
+ defaultProps: {
80
+ enableColorOnDark: true,
81
+ },
82
+ styleOverrides: {
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ primary: (props) => {
85
+ return props.theme.palette.primary.main;
86
+ },
87
+ },
88
+ },
89
+ },
90
+ };
91
+ }
92
+ function getDarkMinimalTheme() {
93
+ return {
94
+ name: 'Dark (minimal)',
95
+ palette: {
96
+ mode: 'dark',
97
+ primary: { main: colors_1.grey[700] },
98
+ secondary: { main: colors_1.grey[800] },
99
+ tertiary: refTheme.palette.augmentColor({ color: { main: colors_1.grey[900] } }),
100
+ quaternary: refTheme.palette.augmentColor({ color: { main: mandarin } }),
101
+ stopCodon: '#e22',
102
+ startCodon: '#3e3',
103
+ bases: {
104
+ A: refTheme.palette.augmentColor({ color: colors_1.green }),
105
+ C: refTheme.palette.augmentColor({ color: colors_1.blue }),
106
+ G: refTheme.palette.augmentColor({ color: colors_1.amber }),
107
+ T: refTheme.palette.augmentColor({ color: colors_1.red }),
108
+ },
109
+ },
110
+ };
111
+ }
112
+ function getMinimalTheme() {
113
+ return {
114
+ name: 'Light (minimal)',
115
+ palette: {
116
+ primary: { main: colors_1.grey[900] },
117
+ secondary: { main: colors_1.grey[800] },
118
+ tertiary: refTheme.palette.augmentColor({ color: { main: colors_1.grey[900] } }),
119
+ quaternary: refTheme.palette.augmentColor({ color: { main: mandarin } }),
120
+ stopCodon: '#e22',
121
+ startCodon: '#3e3',
122
+ bases: {
123
+ A: refTheme.palette.augmentColor({ color: colors_1.green }),
124
+ C: refTheme.palette.augmentColor({ color: colors_1.blue }),
125
+ G: refTheme.palette.augmentColor({ color: colors_1.amber }),
126
+ T: refTheme.palette.augmentColor({ color: colors_1.red }),
127
+ },
128
+ },
129
+ };
130
+ }
131
+ exports.defaultThemes = {
132
+ default: getDefaultTheme(),
133
+ lightStock: getLightStockTheme(),
134
+ lightMinimal: getMinimalTheme(),
135
+ darkMinimal: getDarkMinimalTheme(),
136
+ darkStock: getDarkStockTheme(),
29
137
  };
30
- function createJBrowseDefaultProps( /* palette: PaletteOptions = {} */) {
138
+ function createDefaultProps(theme) {
139
+ var _a, _b, _c, _d, _e, _f;
31
140
  return {
32
141
  components: {
33
142
  MuiButton: {
34
143
  defaultProps: {
35
144
  size: 'small',
36
145
  },
146
+ styleOverrides: {
147
+ // the default button, especially when not using variant=contained, uses
148
+ // theme.palette.primary.main for text which is very bad with dark
149
+ // mode+midnight primary
150
+ //
151
+ // keeps text secondary for darkmode, uses
152
+ // a text-like coloring to ensure contrast
153
+ // xref https://stackoverflow.com/a/72546130/2129219
154
+ //
155
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
156
+ root: (props) => {
157
+ const { theme } = props;
158
+ return theme.palette.mode === 'dark'
159
+ ? {
160
+ color: theme.palette.text.primary,
161
+ }
162
+ : undefined;
163
+ },
164
+ },
37
165
  },
38
166
  MuiAccordion: {
39
167
  defaultProps: {
@@ -96,6 +224,12 @@ function createJBrowseDefaultProps( /* palette: PaletteOptions = {} */) {
96
224
  defaultProps: {
97
225
  size: 'small',
98
226
  },
227
+ styleOverrides: {
228
+ secondary: {
229
+ // @ts-ignore
230
+ backgroundColor: (_b = (_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.quaternary) === null || _b === void 0 ? void 0 : _b.main,
231
+ },
232
+ },
99
233
  },
100
234
  MuiTable: {
101
235
  defaultProps: {
@@ -128,66 +262,125 @@ function createJBrowseDefaultProps( /* palette: PaletteOptions = {} */) {
128
262
  variant: 'standard',
129
263
  },
130
264
  },
131
- },
132
- };
133
- }
134
- exports.createJBrowseDefaultProps = createJBrowseDefaultProps;
135
- function createJBrowseDefaultOverrides(palette = {}) {
136
- const generatedPalette = (0, deepmerge_1.default)(exports.jbrowseDefaultPalette, palette);
137
- return {
138
- components: {
139
- MuiIconButton: {
265
+ MuiLink: {
140
266
  styleOverrides: {
141
- colorSecondary: {
142
- color: generatedPalette.tertiary.main,
143
- },
267
+ // the default link color uses theme.palette.primary.main which is
268
+ // very bad with dark mode+midnight primary
269
+ //
270
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
271
+ root: ({ theme }) => ({
272
+ color: theme.palette.text.secondary,
273
+ }),
144
274
  },
145
275
  },
146
- MuiButton: {
276
+ MuiCheckbox: {
147
277
  styleOverrides: {
148
- textSecondary: {
149
- color: generatedPalette.tertiary.main,
278
+ // the default checkbox-when-checked color uses
279
+ // theme.palette.primary.main which is very bad with dark
280
+ // mode+midnight primary
281
+ //
282
+ // keeps the forest-green checkbox by default but for darkmode, uses
283
+ // a text-like coloring to ensure contrast
284
+ // xref https://stackoverflow.com/a/72546130/2129219
285
+ //
286
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
287
+ root: (props) => {
288
+ const { theme } = props;
289
+ return theme.palette.mode === 'dark'
290
+ ? {
291
+ color: theme.palette.text.secondary,
292
+ '&.Mui-checked': {
293
+ color: theme.palette.text.secondary,
294
+ },
295
+ }
296
+ : undefined;
150
297
  },
151
298
  },
152
299
  },
153
- MuiFab: {
300
+ MuiRadio: {
154
301
  styleOverrides: {
155
- secondary: {
156
- backgroundColor: generatedPalette.quaternary.main,
302
+ // the default checkbox-when-checked color uses
303
+ // theme.palette.primary.main which is very bad with dark
304
+ // mode+midnight primary
305
+ //
306
+ // keeps the forest-green checkbox by default but for darkmode, uses
307
+ // a text-like coloring to ensure contrast
308
+ // xref https://stackoverflow.com/a/72546130/2129219
309
+ //
310
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
311
+ root: (props) => {
312
+ const { theme } = props;
313
+ return theme.palette.mode === 'dark'
314
+ ? {
315
+ color: theme.palette.text.secondary,
316
+ '&.Mui-checked': {
317
+ color: theme.palette.text.secondary,
318
+ },
319
+ }
320
+ : undefined;
157
321
  },
158
322
  },
159
323
  },
160
- MuiLink: {
324
+ MuiFormLabel: {
161
325
  styleOverrides: {
162
- root: {
163
- color: generatedPalette.tertiary.main,
326
+ // the default checkbox-when-checked color uses
327
+ // theme.palette.primary.main which is very bad with dark
328
+ // mode+midnight primary
329
+ //
330
+ // keeps the forest-green checkbox by default but for darkmode, uses
331
+ // a text-like coloring to ensure contrast
332
+ // xref https://stackoverflow.com/a/72546130/2129219
333
+ //
334
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
335
+ root: (props) => {
336
+ const { theme } = props;
337
+ return theme.palette.mode === 'dark'
338
+ ? {
339
+ color: theme.palette.text.secondary,
340
+ '&.Mui-focused': {
341
+ color: theme.palette.text.secondary,
342
+ },
343
+ }
344
+ : undefined;
164
345
  },
165
346
  },
166
347
  },
167
348
  MuiAccordionSummary: {
168
349
  styleOverrides: {
169
350
  root: {
170
- backgroundColor: generatedPalette.tertiary.main,
351
+ // @ts-ignore
352
+ backgroundColor: (_d = (_c = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _c === void 0 ? void 0 : _c.tertiary) === null || _d === void 0 ? void 0 : _d.main,
171
353
  },
172
354
  content: {
173
- color: generatedPalette.tertiary.contrastText,
355
+ // @ts-ignore
356
+ color: (_f = (_e = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _e === void 0 ? void 0 : _e.tertiary) === null || _f === void 0 ? void 0 : _f.contrastText,
174
357
  },
175
358
  },
176
359
  },
360
+ MuiToggleButtonGroup: {
361
+ defaultProps: {
362
+ size: 'small',
363
+ },
364
+ },
177
365
  },
178
366
  };
179
367
  }
180
- exports.createJBrowseDefaultOverrides = createJBrowseDefaultOverrides;
181
- function createJBrowseBaseTheme(palette) {
182
- return {
183
- palette: exports.jbrowseDefaultPalette,
368
+ function createJBrowseBaseTheme(theme) {
369
+ return (0, deepmerge_1.default)({
370
+ palette: theme === null || theme === void 0 ? void 0 : theme.palette,
184
371
  typography: { fontSize: 12 },
185
372
  spacing: 4,
186
- ...(0, deepmerge_1.default)(createJBrowseDefaultProps(), createJBrowseDefaultOverrides(palette)),
187
- };
373
+ ...createDefaultProps(theme),
374
+ }, theme || {});
188
375
  }
189
376
  exports.createJBrowseBaseTheme = createJBrowseBaseTheme;
190
- function createJBrowseTheme(theme) {
377
+ function createJBrowseTheme(configTheme = {}, themes = exports.defaultThemes, themeName = 'default') {
378
+ return (0, styles_1.createTheme)(createJBrowseBaseTheme(themeName === 'default'
379
+ ? (0, deepmerge_1.default)(themes['default'], augmentTheme(configTheme))
380
+ : augmentThemePlus(themes[themeName]) || themes['default']));
381
+ }
382
+ exports.createJBrowseTheme = createJBrowseTheme;
383
+ function augmentTheme(theme = {}) {
191
384
  var _a, _b;
192
385
  if ((_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.tertiary) {
193
386
  theme = (0, deepmerge_1.default)(theme, {
@@ -207,6 +400,25 @@ function createJBrowseTheme(theme) {
207
400
  },
208
401
  });
209
402
  }
210
- return (0, styles_1.createTheme)((0, deepmerge_1.default)(createJBrowseBaseTheme(theme === null || theme === void 0 ? void 0 : theme.palette), theme || {}));
403
+ return theme;
404
+ }
405
+ // creates some blank quaternary/tertiary colors if unsupplied by a user theme
406
+ function augmentThemePlus(theme = {}) {
407
+ var _a, _b;
408
+ theme = augmentTheme(theme);
409
+ if (!((_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.quaternary)) {
410
+ theme = (0, deepmerge_1.default)(theme, {
411
+ palette: {
412
+ quaternary: refTheme.palette.augmentColor({ color: { main: '#aaa' } }),
413
+ },
414
+ });
415
+ }
416
+ if (!((_b = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _b === void 0 ? void 0 : _b.tertiary)) {
417
+ theme = (0, deepmerge_1.default)(theme, {
418
+ palette: {
419
+ tertiary: refTheme.palette.augmentColor({ color: { main: '#aaa' } }),
420
+ },
421
+ });
422
+ }
423
+ return theme;
211
424
  }
212
- exports.createJBrowseTheme = createJBrowseTheme;
package/util/index.d.ts CHANGED
@@ -348,7 +348,8 @@ export declare function getEnv(obj: any): {
348
348
  pluginManager: PluginManager;
349
349
  };
350
350
  export declare function localStorageGetItem(item: string): string | null | undefined;
351
- export declare function max(arr: number[]): number;
352
- export declare function min(arr: number[]): number;
351
+ export declare function localStorageSetItem(str: string, item: string): void;
352
+ export declare function max(arr: number[], init?: number): number;
353
+ export declare function min(arr: number[], init?: number): number;
353
354
  export declare function sum(arr: number[]): number;
354
355
  export declare function avg(arr: number[]): number;
package/util/index.js CHANGED
@@ -30,7 +30,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
30
30
  };
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
32
  exports.bytesForRegions = exports.objectHash = exports.hashCode = exports.updateStatus = exports.generateCodonTable = exports.defaultCodonTable = exports.defaultStops = exports.defaultStarts = exports.measureText = exports.rIC = exports.blobToDataURL = exports.complement = exports.reverse = exports.revcom = exports.isElectron = exports.stringify = exports.shorten = exports.minmax = exports.renameRegionsIfNeeded = exports.renameRegionIfNeeded = exports.makeAbortableReaction = exports.findLastIndex = exports.iterMap = exports.bpSpanPx = exports.featureSpanPx = exports.cartesianToPolar = exports.polarToCartesian = exports.degToRad = exports.radToDeg = exports.bpToPx = exports.clamp = exports.compareLocStrings = exports.compareLocs = exports.parseLocString = exports.parseLocStringOneBased = exports.assembleLocStringFast = exports.assembleLocString = exports.getContainingDisplay = exports.getContainingTrack = exports.getContainingView = exports.getSession = exports.findParentThatIs = exports.springAnimate = exports.findParentThat = exports.useDebouncedCallback = exports.useDebounce = exports.inProduction = exports.inDevelopment = exports.isFeature = exports.SimpleFeature = void 0;
33
- exports.avg = exports.sum = exports.min = exports.max = exports.localStorageGetItem = exports.getEnv = exports.measureGridWidth = exports.getStr = exports.getUriLink = exports.useLocalStorage = exports.getLayoutId = exports.getViewParams = exports.getTickDisplayStr = exports.toLocale = exports.getBpDisplayStr = exports.supportedIndexingAdapters = void 0;
33
+ exports.avg = exports.sum = exports.min = exports.max = exports.localStorageSetItem = exports.localStorageGetItem = exports.getEnv = exports.measureGridWidth = exports.getStr = exports.getUriLink = exports.useLocalStorage = exports.getLayoutId = exports.getViewParams = exports.getTickDisplayStr = exports.toLocale = exports.getBpDisplayStr = exports.supportedIndexingAdapters = void 0;
34
34
  /* eslint-disable @typescript-eslint/no-explicit-any */
35
35
  const react_1 = require("react");
36
36
  const is_object_1 = __importDefault(require("is-object"));
@@ -1028,16 +1028,22 @@ function localStorageGetItem(item) {
1028
1028
  : undefined;
1029
1029
  }
1030
1030
  exports.localStorageGetItem = localStorageGetItem;
1031
- function max(arr) {
1032
- let max = -Infinity;
1031
+ function localStorageSetItem(str, item) {
1032
+ return typeof localStorage !== 'undefined'
1033
+ ? localStorage.setItem(str, item)
1034
+ : undefined;
1035
+ }
1036
+ exports.localStorageSetItem = localStorageSetItem;
1037
+ function max(arr, init = -Infinity) {
1038
+ let max = init;
1033
1039
  for (let i = 0; i < arr.length; i++) {
1034
1040
  max = arr[i] > max ? arr[i] : max;
1035
1041
  }
1036
1042
  return max;
1037
1043
  }
1038
1044
  exports.max = max;
1039
- function min(arr) {
1040
- let min = Infinity;
1045
+ function min(arr, init = Infinity) {
1046
+ let min = init;
1041
1047
  for (let i = 0; i < arr.length; i++) {
1042
1048
  min = arr[i] < min ? arr[i] : min;
1043
1049
  }
@@ -0,0 +1,3 @@
1
+ type Obj = Record<string, unknown>;
2
+ export default function map(object: Obj, mapper: (val: unknown) => void, isSeen?: WeakSet<object>): void;
3
+ export {};
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // adapted from map-obj (MIT), with modifications to pass the "whole object"
4
+ // from an array of objects into itself
5
+ const isObject = (value) => typeof value === 'object' && value !== null;
6
+ // Customized for this use-case
7
+ const isObjectCustom = (value) => isObject(value) &&
8
+ !(value instanceof RegExp) &&
9
+ !(value instanceof Error) &&
10
+ !(value instanceof Date) &&
11
+ !(globalThis.Blob && value instanceof globalThis.Blob);
12
+ function map(object, mapper, isSeen = new WeakSet()) {
13
+ if (isSeen.has(object)) {
14
+ return;
15
+ }
16
+ isSeen.add(object);
17
+ const mapArray = (array) => array.forEach(element => {
18
+ mapper(element);
19
+ if (isObject(element)) {
20
+ map(element, mapper, isSeen);
21
+ }
22
+ });
23
+ if (Array.isArray(object)) {
24
+ mapArray(object);
25
+ }
26
+ for (const value of Object.values(object)) {
27
+ mapper(value);
28
+ if (isObjectCustom(value)) {
29
+ Array.isArray(value) ? mapArray(value) : map(value, mapper, isSeen);
30
+ }
31
+ }
32
+ }
33
+ exports.default = map;
@@ -1,14 +1,28 @@
1
- /// <reference types="react" />
2
- export type RenderReturn = Record<string, unknown>;
1
+ import React from 'react';
2
+ export type RenderReturn = Record<string, unknown> | void;
3
+ type RendererRet = Promise<RenderReturn> | RenderReturn;
3
4
  export declare function renderToAbstractCanvas(width: number, height: number, opts: {
4
5
  exportSVG?: {
5
6
  rasterizeLayers?: boolean;
7
+ scale?: number;
6
8
  };
7
- highResolutionScaling: number;
8
- }, cb: (ctx: CanvasRenderingContext2D) => Promise<RenderReturn | void> | RenderReturn | void): Promise<{
9
+ highResolutionScaling?: number;
10
+ }, cb: (ctx: CanvasRenderingContext2D) => RendererRet): Promise<{
9
11
  canvasRecordedData: any;
10
12
  } | {
11
13
  reactElement: JSX.Element;
12
14
  } | {
13
15
  imageData: any;
14
16
  }>;
17
+ export declare function getSerializedSvg(results: {
18
+ width: number;
19
+ height: number;
20
+ canvasRecordedData: unknown;
21
+ }): Promise<string>;
22
+ export declare function ReactRendering({ rendering, }: {
23
+ rendering: {
24
+ reactElement?: React.ReactNode;
25
+ html?: string;
26
+ };
27
+ }): JSX.Element;
28
+ export {};
@@ -1,16 +1,39 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.renderToAbstractCanvas = void 0;
29
+ exports.ReactRendering = exports.getSerializedSvg = exports.renderToAbstractCanvas = void 0;
7
30
  const react_1 = __importDefault(require("react"));
8
31
  const canvas_sequencer_1 = require("canvas-sequencer");
9
32
  // locals
10
33
  const offscreenCanvasPonyfill_1 = require("./offscreenCanvasPonyfill");
11
34
  const index_1 = require("./index");
12
35
  async function renderToAbstractCanvas(width, height, opts, cb) {
13
- const { exportSVG, highResolutionScaling: scaling = 1 } = opts;
36
+ const { exportSVG, highResolutionScaling = 1 } = opts;
14
37
  if (exportSVG) {
15
38
  if (!exportSVG.rasterizeLayers) {
16
39
  const fakeCtx = new canvas_sequencer_1.CanvasSequence();
@@ -21,13 +44,13 @@ async function renderToAbstractCanvas(width, height, opts, cb) {
21
44
  };
22
45
  }
23
46
  else {
24
- const scale = 4;
25
- const canvas = (0, offscreenCanvasPonyfill_1.createCanvas)(Math.ceil(width * scale), height * scale);
47
+ const s = exportSVG.scale || highResolutionScaling;
48
+ const canvas = (0, offscreenCanvasPonyfill_1.createCanvas)(Math.ceil(width * s), height * s);
26
49
  const ctx = canvas.getContext('2d');
27
50
  if (!ctx) {
28
51
  throw new Error('2d canvas rendering not supported on this platform');
29
52
  }
30
- ctx.scale(scale, scale);
53
+ ctx.scale(s, s);
31
54
  const result = await cb(ctx);
32
55
  // two methods needed for converting canvas to PNG, one for webworker
33
56
  // offscreen canvas, one for main thread
@@ -42,14 +65,32 @@ async function renderToAbstractCanvas(width, height, opts, cb) {
42
65
  }
43
66
  }
44
67
  else {
45
- const canvas = (0, offscreenCanvasPonyfill_1.createCanvas)(Math.ceil(width * scaling), height * scaling);
68
+ const s = highResolutionScaling;
69
+ const canvas = (0, offscreenCanvasPonyfill_1.createCanvas)(Math.ceil(width * s), height * s);
46
70
  const ctx = canvas.getContext('2d');
47
71
  if (!ctx) {
48
72
  throw new Error('2d canvas rendering not supported on this platform');
49
73
  }
50
- ctx.scale(scaling, scaling);
74
+ ctx.scale(s, s);
51
75
  const result = await cb(ctx);
52
76
  return { ...result, imageData: await (0, offscreenCanvasPonyfill_1.createImageBitmap)(canvas) };
53
77
  }
54
78
  }
55
79
  exports.renderToAbstractCanvas = renderToAbstractCanvas;
80
+ async function getSerializedSvg(results) {
81
+ const { width, height, canvasRecordedData } = results;
82
+ const C2S = await Promise.resolve().then(() => __importStar(require('canvas2svg')));
83
+ const ctx = new C2S.default(width, height);
84
+ const seq = new canvas_sequencer_1.CanvasSequence(canvasRecordedData);
85
+ seq.execute(ctx);
86
+ // innerHTML strips the outer <svg> element from returned data, we add
87
+ // our own <svg> element in the view's SVG export
88
+ return ctx.getSvg().innerHTML;
89
+ }
90
+ exports.getSerializedSvg = getSerializedSvg;
91
+ function ReactRendering({ rendering, }) {
92
+ return (react_1.default.createElement(react_1.default.Fragment, null, react_1.default.isValidElement(rendering.reactElement) ? (rendering.reactElement) : (react_1.default.createElement("g", {
93
+ /* eslint-disable-next-line react/no-danger */
94
+ dangerouslySetInnerHTML: { __html: rendering.html || '' } }))));
95
+ }
96
+ exports.ReactRendering = ReactRendering;
@@ -1,8 +0,0 @@
1
- import SimpleFeature from '../util/simpleFeature';
2
- import { BaseAdapter } from './BaseAdapter';
3
- declare const configSchema: import("../configuration").AnyConfigurationSchemaType;
4
- declare class CytobandAdapter extends BaseAdapter {
5
- getData(): Promise<SimpleFeature[]>;
6
- freeResources(): void;
7
- }
8
- export { configSchema, CytobandAdapter as DataAdapter };
@@ -1,49 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DataAdapter = exports.configSchema = void 0;
7
- const simpleFeature_1 = __importDefault(require("../util/simpleFeature"));
8
- const configuration_1 = require("../configuration");
9
- const io_1 = require("../util/io");
10
- const BaseAdapter_1 = require("./BaseAdapter");
11
- /**
12
- * #config CytobandAdapter
13
- */
14
- function x() { } // eslint-disable-line @typescript-eslint/no-unused-vars
15
- const configSchema = (0, configuration_1.ConfigurationSchema)('CytobandAdapter', {
16
- /**
17
- * #slot
18
- */
19
- cytobandLocation: {
20
- type: 'fileLocation',
21
- defaultValue: { uri: '/path/to/cytoband.txt.gz' },
22
- },
23
- }, { explicitlyTyped: true });
24
- exports.configSchema = configSchema;
25
- class CytobandAdapter extends BaseAdapter_1.BaseAdapter {
26
- async getData() {
27
- const loc = (0, configuration_1.readConfObject)(this.config, 'cytobandLocation');
28
- if (loc.uri === '' || loc.uri === '/path/to/cytoband.txt.gz') {
29
- return [];
30
- }
31
- const data = await (0, io_1.openLocation)(loc).readFile('utf8');
32
- return data
33
- .split(/\n|\r\n|\r/)
34
- .filter(f => !!f.trim())
35
- .map(line => {
36
- const [refName, start, end, name, type] = line.split('\t');
37
- return new simpleFeature_1.default({
38
- uniqueId: line,
39
- refName,
40
- start: +start,
41
- end: +end,
42
- name,
43
- type,
44
- });
45
- });
46
- }
47
- freeResources( /* { region } */) { }
48
- }
49
- exports.DataAdapter = CytobandAdapter;