@jbrowse/product-core 4.3.0 → 5.0.0-beta.10
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.
- package/esm/RootModel/BaseRootModel.d.ts +514 -323
- package/esm/RootModel/BaseRootModel.js +141 -14
- package/esm/RootModel/HierarchicalConfig.d.ts +30 -20
- package/esm/RootModel/HierarchicalConfig.js +36 -0
- package/esm/RootModel/InternetAccounts.d.ts +18 -1
- package/esm/RootModel/InternetAccounts.js +120 -22
- package/esm/RootModel/PreferencesConfig.d.ts +37 -0
- package/esm/RootModel/PreferencesConfig.js +75 -0
- package/esm/RootModel/createConfigModel.d.ts +257 -0
- package/esm/RootModel/createConfigModel.js +77 -0
- package/esm/RootModel/index.d.ts +10 -5
- package/esm/RootModel/index.js +10 -5
- package/esm/RootModel/menuItems.d.ts +24 -0
- package/esm/RootModel/menuItems.js +141 -0
- package/esm/Session/BaseSession.d.ts +285 -11
- package/esm/Session/BaseSession.js +383 -15
- package/esm/Session/Connections.d.ts +115 -8
- package/esm/Session/Connections.js +196 -74
- package/esm/Session/DrawerWidgets.d.ts +145 -13
- package/esm/Session/DrawerWidgets.js +219 -49
- package/esm/Session/MultipleViews.d.ts +1067 -1177
- package/esm/Session/MultipleViews.js +395 -64
- package/esm/Session/Preferences.d.ts +1389 -0
- package/esm/Session/Preferences.js +58 -0
- package/esm/Session/ReferenceManagement.d.ts +28 -3
- package/esm/Session/ReferenceManagement.js +56 -41
- package/esm/Session/SessionTracks.d.ts +1101 -1180
- package/esm/Session/SessionTracks.js +584 -34
- package/esm/Session/Themes.d.ts +136 -2
- package/esm/Session/Themes.js +267 -21
- package/esm/Session/TrackMenu.d.ts +88 -0
- package/esm/Session/TrackMenu.js +175 -0
- package/esm/Session/TrackMenuSessionMixin.d.ts +27 -0
- package/esm/Session/TrackMenuSessionMixin.js +42 -0
- package/esm/Session/Tracks.d.ts +945 -1159
- package/esm/Session/Tracks.js +229 -30
- package/esm/Session/assertSessionModel.d.ts +21 -0
- package/esm/Session/assertSessionModel.js +1 -0
- package/esm/Session/copyTrackSnapshot.d.ts +21 -0
- package/esm/Session/copyTrackSnapshot.js +20 -0
- package/esm/Session/developerMode.d.ts +7 -0
- package/esm/Session/developerMode.js +43 -0
- package/esm/Session/finalizeSession.d.ts +15 -0
- package/esm/Session/finalizeSession.js +28 -0
- package/esm/Session/hydratedForms.d.ts +16 -0
- package/esm/Session/hydratedForms.js +13 -0
- package/esm/Session/index.d.ts +27 -10
- package/esm/Session/index.js +16 -10
- package/esm/Session/pluginExtraTrackItems.d.ts +11 -0
- package/esm/Session/pluginExtraTrackItems.js +13 -0
- package/esm/Session/readdedTrackConf.d.ts +8 -0
- package/esm/Session/readdedTrackConf.js +24 -0
- package/esm/Session/shareableSnapshot.d.ts +23 -0
- package/esm/Session/shareableSnapshot.js +66 -0
- package/esm/Session/temporaryAssemblyTracks.d.ts +24 -0
- package/esm/Session/temporaryAssemblyTracks.js +37 -0
- package/esm/assertExtends.d.ts +55 -0
- package/esm/assertExtends.js +1 -0
- package/esm/controllerTracks.d.ts +76 -0
- package/esm/controllerTracks.js +125 -0
- package/esm/destroyViewState.d.ts +21 -0
- package/esm/destroyViewState.js +29 -0
- package/esm/embeddedController.d.ts +57 -0
- package/esm/embeddedController.js +100 -0
- package/esm/index.d.ts +32 -4
- package/esm/index.js +31 -4
- package/esm/loadPlugins.d.ts +38 -0
- package/esm/loadPlugins.js +45 -0
- package/esm/localFiles.d.ts +74 -0
- package/esm/localFiles.js +156 -0
- package/esm/observeSession.d.ts +55 -0
- package/esm/observeSession.js +90 -0
- package/esm/parallelChunkLoading.d.ts +30 -0
- package/esm/parallelChunkLoading.js +71 -0
- package/esm/pluginInput.d.ts +32 -0
- package/esm/pluginInput.js +19 -0
- package/esm/pruneUnbuildableNodes.d.ts +109 -0
- package/esm/pruneUnbuildableNodes.js +562 -0
- package/esm/resolveAssemblies.d.ts +68 -0
- package/esm/resolveAssemblies.js +77 -0
- package/esm/rpcWorker.d.ts +36 -4
- package/esm/rpcWorker.js +126 -20
- package/esm/sessionMigrations/index.d.ts +15 -0
- package/esm/sessionMigrations/index.js +178 -0
- package/esm/sessionUrl.d.ts +40 -0
- package/esm/sessionUrl.js +66 -0
- package/esm/sessionUtils.d.ts +74 -0
- package/esm/sessionUtils.js +599 -0
- package/esm/siblingCast.d.ts +14 -0
- package/esm/siblingCast.js +16 -0
- package/esm/snapshotUtils.d.ts +8 -0
- package/esm/snapshotUtils.js +12 -0
- package/esm/ui/AboutDialog.d.ts +8 -3
- package/esm/ui/AboutDialog.js +14 -5
- package/esm/ui/AboutDialogContents.d.ts +2 -6
- package/esm/ui/AboutDialogContents.js +13 -17
- package/esm/ui/AssemblyInfoPanel.d.ts +5 -0
- package/esm/ui/AssemblyInfoPanel.js +63 -0
- package/esm/ui/DescriptionPanel.d.ts +3 -0
- package/esm/ui/DescriptionPanel.js +25 -0
- package/esm/ui/Drawer.d.ts +21 -0
- package/esm/ui/Drawer.js +60 -0
- package/esm/ui/DrawerControls.d.ts +5 -0
- package/esm/ui/DrawerControls.js +28 -0
- package/esm/ui/DrawerHeader.d.ts +6 -0
- package/esm/ui/DrawerHeader.js +36 -0
- package/esm/ui/DrawerWidget.d.ts +5 -0
- package/esm/ui/DrawerWidget.js +12 -0
- package/esm/ui/DrawerWidgetSelector.d.ts +5 -0
- package/esm/ui/DrawerWidgetSelector.js +40 -0
- package/esm/ui/FileInfoPanel.d.ts +3 -6
- package/esm/ui/FileInfoPanel.js +36 -26
- package/esm/ui/GeneralPreferencesTab.d.ts +17 -0
- package/esm/ui/GeneralPreferencesTab.js +34 -0
- package/esm/ui/HeaderButtons.d.ts +2 -1
- package/esm/ui/HeaderButtons.js +15 -17
- package/esm/ui/ModalWidget.d.ts +13 -0
- package/esm/ui/ModalWidget.js +48 -0
- package/esm/ui/ModalWidgetAppBar.d.ts +8 -0
- package/esm/ui/ModalWidgetAppBar.js +9 -0
- package/esm/ui/PreferenceCheckbox.d.ts +6 -0
- package/esm/ui/PreferenceCheckbox.js +16 -0
- package/esm/ui/PreferencesDialog.d.ts +34 -0
- package/esm/ui/PreferencesDialog.js +55 -0
- package/esm/ui/PreferencesResetDialog.d.ts +8 -0
- package/esm/ui/PreferencesResetDialog.js +19 -0
- package/esm/ui/RefNameAliasesDialog.d.ts +9 -0
- package/esm/ui/RefNameAliasesDialog.js +65 -0
- package/esm/ui/RefNameInfoDialog.d.ts +3 -6
- package/esm/ui/RefNameInfoDialog.js +45 -63
- package/esm/ui/ViewPreferencesTab.d.ts +12 -0
- package/esm/ui/ViewPreferencesTab.js +15 -0
- package/esm/ui/WidgetBody.d.ts +18 -0
- package/esm/ui/WidgetBody.js +22 -0
- package/esm/ui/WidgetHeading.d.ts +7 -0
- package/esm/ui/WidgetHeading.js +7 -0
- package/esm/ui/aboutTestUtils.d.ts +140 -0
- package/esm/ui/aboutTestUtils.js +25 -0
- package/esm/ui/descriptionHtml.d.ts +25 -0
- package/esm/ui/descriptionHtml.js +64 -0
- package/esm/ui/drawerLayout.d.ts +18 -0
- package/esm/ui/drawerLayout.js +22 -0
- package/esm/ui/index.d.ts +15 -1
- package/esm/ui/index.js +13 -1
- package/esm/ui/preferencesReset.d.ts +18 -0
- package/esm/ui/preferencesReset.js +69 -0
- package/esm/ui/util.d.ts +22 -7
- package/esm/ui/util.js +19 -41
- package/esm/useEngineLifecycle.d.ts +19 -0
- package/esm/useEngineLifecycle.js +44 -0
- package/package.json +15 -18
- package/esm/RootModel/FormatAbout.d.ts +0 -12
- package/esm/RootModel/FormatAbout.js +0 -15
- package/esm/RootModel/FormatDetails.d.ts +0 -24
- package/esm/RootModel/FormatDetails.js +0 -27
- package/esm/Session/DialogQueue.d.ts +0 -17
- package/esm/Session/DialogQueue.js +0 -31
package/esm/Session/Themes.d.ts
CHANGED
|
@@ -1,18 +1,152 @@
|
|
|
1
1
|
import type PluginManager from '@jbrowse/core/PluginManager';
|
|
2
|
+
import type { PaletteMode } from '@jbrowse/core/ui/palette';
|
|
3
|
+
import type { SerializableThemeArgs, ThemeMap } from '@jbrowse/core/ui/theme';
|
|
2
4
|
import type { IAnyStateTreeNode, Instance } from '@jbrowse/mobx-state-tree';
|
|
3
5
|
import type { ThemeOptions } from '@mui/material';
|
|
4
|
-
|
|
6
|
+
/** The three the mode picker offers; `system` follows the OS preference. */
|
|
7
|
+
export type ThemeModeSelection = PaletteMode | 'system';
|
|
8
|
+
/**
|
|
9
|
+
* The theme the stored selection resolves to, for UI drawn before a session
|
|
10
|
+
* exists, such as Desktop's start screen.
|
|
11
|
+
*/
|
|
12
|
+
export declare function storedThemeArgs(): SerializableThemeArgs;
|
|
13
|
+
/**
|
|
14
|
+
* #stateModel ThemeManagerSessionMixin
|
|
15
|
+
*/
|
|
5
16
|
export declare function ThemeManagerSessionMixin(_pluginManager: PluginManager): import("@jbrowse/mobx-state-tree").IModelType<{}, {
|
|
6
17
|
sessionThemeName: string;
|
|
18
|
+
sessionThemeMode: ThemeModeSelection;
|
|
19
|
+
systemThemeOverride: PaletteMode | undefined;
|
|
20
|
+
systemPrefersDark: boolean;
|
|
7
21
|
} & {
|
|
22
|
+
/**
|
|
23
|
+
* #method
|
|
24
|
+
*/
|
|
8
25
|
allThemes(): ThemeMap;
|
|
26
|
+
/**
|
|
27
|
+
* #getter
|
|
28
|
+
* Which palette is in effect. A stored name whose theme an admin has
|
|
29
|
+
* since dropped reads as `default` without the stored value being
|
|
30
|
+
* touched, so it comes back if the plugin supplying it loads again.
|
|
31
|
+
*/
|
|
9
32
|
readonly themeName: string;
|
|
33
|
+
/**
|
|
34
|
+
* #getter
|
|
35
|
+
* Light, dark, or following the OS — the axis the palette is drawn
|
|
36
|
+
* along, and what the mode picker shows. `effectiveThemeMode` is the
|
|
37
|
+
* one to read for a colour decision.
|
|
38
|
+
*/
|
|
39
|
+
readonly themeMode: ThemeModeSelection;
|
|
40
|
+
/**
|
|
41
|
+
* #getter
|
|
42
|
+
* Light or dark, with `system` resolved against the OS preference or
|
|
43
|
+
* the toolbar's hold on the other mode.
|
|
44
|
+
*/
|
|
45
|
+
readonly effectiveThemeMode: PaletteMode;
|
|
46
|
+
/**
|
|
47
|
+
* #getter
|
|
48
|
+
* Whether what is drawn right now is dark. Read off the resolved
|
|
49
|
+
* palette rather than the mode, so a palette pinned to one mode — an
|
|
50
|
+
* `extraThemes` entry declaring `mode: 'dark'` — answers for itself.
|
|
51
|
+
*/
|
|
52
|
+
readonly themeIsDark: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* #getter
|
|
55
|
+
*/
|
|
56
|
+
readonly themeOptions: SerializableThemeArgs;
|
|
57
|
+
/**
|
|
58
|
+
* #getter
|
|
59
|
+
* Every color JBrowse renders, resolved to plain strings. This is what
|
|
60
|
+
* rendering reads: it needs no React context, it crosses the RPC worker
|
|
61
|
+
* boundary as itself, and it costs no UI toolkit. Prefer it over
|
|
62
|
+
* `theme` anywhere the answer wanted is a color rather than a Material
|
|
63
|
+
* UI component style.
|
|
64
|
+
*/
|
|
65
|
+
readonly palette: import("@jbrowse/core/ui/palette").JBrowsePalette;
|
|
66
|
+
/**
|
|
67
|
+
* #getter
|
|
68
|
+
* The palette plus the sizing tokens `makeStyles` reads — spacing,
|
|
69
|
+
* corner radius, type scale. This is what a product mounts on
|
|
70
|
+
* `StyleThemeProvider`; it costs no UI toolkit, and it is derived from
|
|
71
|
+
* the same `themeOptions` as `theme`, so a config `theme` that sets
|
|
72
|
+
* `spacing` moves JBrowse's own styles and its Material components
|
|
73
|
+
* together.
|
|
74
|
+
*/
|
|
75
|
+
readonly styleTheme: import("@jbrowse/core/ui/styleTheme").JBrowseStyleTheme;
|
|
76
|
+
/**
|
|
77
|
+
* #getter
|
|
78
|
+
* The Material UI theme, for the components that are Material UI. Its
|
|
79
|
+
* palette is spliced from the same `resolvePalette` call as `palette`
|
|
80
|
+
* above, so the two cannot disagree.
|
|
81
|
+
*/
|
|
10
82
|
readonly theme: import("@mui/material").Theme;
|
|
83
|
+
/**
|
|
84
|
+
* #method
|
|
85
|
+
* Raw `ThemeOptions` for the active theme, or a named override (used by
|
|
86
|
+
* the SVG-export theme picker). Unlike `theme` (a built,
|
|
87
|
+
* non-serializable MUI theme), this is the plain options object every
|
|
88
|
+
* view's SVG export threads into each display's `renderSvg`, which
|
|
89
|
+
* rebuilds the theme via `createJBrowseTheme` outside React context.
|
|
90
|
+
*
|
|
91
|
+
* The `default` entry is merged with the config `theme` slot, because
|
|
92
|
+
* the picker labels it "Default (from config)" and `resolvePalette`
|
|
93
|
+
* merges the preset with the slot for every other consumer. The bare
|
|
94
|
+
* preset would make `view.exportSvg()` drop a host's configured
|
|
95
|
+
* palette: a config setting `primary.main` would draw `#123456` on
|
|
96
|
+
* screen and export the stock `#0D233F`, while the export dialog named
|
|
97
|
+
* the default theme. Every other named theme is a fixed preset that
|
|
98
|
+
* ignores config.
|
|
99
|
+
*
|
|
100
|
+
* **The mode is spliced in here**, because a palette no longer carries
|
|
101
|
+
* one and this is the last point before the export leaves the session:
|
|
102
|
+
* every caller hands `renderSvg` these options and nothing else, so a
|
|
103
|
+
* figure exported from a dark session comes out dark. A palette pinned
|
|
104
|
+
* to its own mode, or a `name` from before the axis, states the mode
|
|
105
|
+
* itself and keeps it.
|
|
106
|
+
*/
|
|
107
|
+
getActiveThemeOptions(name?: string): ThemeOptions;
|
|
11
108
|
} & {
|
|
109
|
+
/**
|
|
110
|
+
* #action
|
|
111
|
+
* Pick a palette. A name from before light and dark were an axis sets
|
|
112
|
+
* the mode it spelled as well, so an old share link, a saved figure spec
|
|
113
|
+
* and `jbrowse-img --theme darkStock` all still mean what they said.
|
|
114
|
+
* Either that or a palette pinned to its own mode drops a held mode,
|
|
115
|
+
* which would otherwise resurface on the next palette change.
|
|
116
|
+
*/
|
|
12
117
|
setThemeName(name: string): void;
|
|
118
|
+
/**
|
|
119
|
+
* #action
|
|
120
|
+
*/
|
|
121
|
+
setSystemPrefersDark(dark: boolean): void;
|
|
122
|
+
/**
|
|
123
|
+
* #action
|
|
124
|
+
* Hold a session that follows the system on the mode the OS is not
|
|
125
|
+
* asking for, or `undefined` to follow it again. The toolbar's sun/moon
|
|
126
|
+
* writes this, so it stays in the toolbar after a click. The OS flipping
|
|
127
|
+
* clears it, since by then the OS has come round to the held mode. The
|
|
128
|
+
* palette is untouched: a reader on Minimal who does this keeps Minimal.
|
|
129
|
+
*/
|
|
130
|
+
setSystemThemeOverride(mode?: PaletteMode): void;
|
|
131
|
+
/**
|
|
132
|
+
* #action
|
|
133
|
+
* Draw the session light or dark, leaving the palette alone. `system`
|
|
134
|
+
* follows the OS preference. Satisfies `ThemeModeSession`, so
|
|
135
|
+
* `useSessionPalette` works against an app session and an embedded one
|
|
136
|
+
* alike, and a host that follows its own dark-mode state calls this.
|
|
137
|
+
*
|
|
138
|
+
* `themeOptions` carries the mode to the RPC worker, so the labels baked
|
|
139
|
+
* into a rendered image follow it along with what React draws. That used
|
|
140
|
+
* to take a write into the config `theme` slot, because mode lived
|
|
141
|
+
* inside a palette and there was nowhere else to put it.
|
|
142
|
+
*/
|
|
143
|
+
setThemeMode(mode: ThemeModeSelection): void;
|
|
144
|
+
} & {
|
|
13
145
|
afterAttach(): void;
|
|
14
146
|
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
147
|
+
/** Session mixin MST type for a session that supports theming */
|
|
15
148
|
export type SessionWithThemesType = ReturnType<typeof ThemeManagerSessionMixin>;
|
|
149
|
+
/** Instance of a session that has theming support */
|
|
16
150
|
export type SessionWithThemes = Instance<SessionWithThemesType>;
|
|
151
|
+
/** Type guard for SessionWithThemes */
|
|
17
152
|
export declare function isSessionWithThemes(session: IAnyStateTreeNode): session is SessionWithThemes;
|
|
18
|
-
export {};
|
package/esm/Session/Themes.js
CHANGED
|
@@ -1,43 +1,289 @@
|
|
|
1
1
|
import { getConf } from '@jbrowse/core/configuration';
|
|
2
|
-
import {
|
|
2
|
+
import { resolvePalette, resolveThemeSelection } from '@jbrowse/core/ui/palette';
|
|
3
|
+
import { resolveStyleTheme } from '@jbrowse/core/ui/styleTheme';
|
|
4
|
+
import { createJBrowseThemeFromArgs, defaultThemes, } from '@jbrowse/core/ui/theme';
|
|
3
5
|
import { localStorageGetItem, localStorageSetItem } from '@jbrowse/core/util';
|
|
6
|
+
import { onColorSchemeChange, prefersDarkColorScheme, } from '@jbrowse/core/util/systemColorScheme';
|
|
4
7
|
import { addDisposer, types } from '@jbrowse/mobx-state-tree';
|
|
5
8
|
import { autorun } from 'mobx';
|
|
9
|
+
import { asSession } from '../siblingCast.js';
|
|
10
|
+
import { isBaseSession } from './BaseSession.js';
|
|
11
|
+
/**
|
|
12
|
+
* What `name` actually resolves to — `default` for one `themes` no longer
|
|
13
|
+
* holds. Every theme name is either stored or handed in from outside, and both
|
|
14
|
+
* go stale the same way: `sessionThemeName` outlives an `extraThemes` entry an
|
|
15
|
+
* admin drops, and so does a name an export dialog persisted or a saved figure
|
|
16
|
+
* spec carries.
|
|
17
|
+
*/
|
|
18
|
+
function resolveThemeName(themes, name) {
|
|
19
|
+
return themes[name] ? name : 'default';
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A session starts light, and follows the OS only when asked to. A dark OS is
|
|
23
|
+
* not a request for a dark genome browser.
|
|
24
|
+
*/
|
|
25
|
+
const DEFAULT_MODE = 'light';
|
|
26
|
+
function systemMode() {
|
|
27
|
+
return prefersDarkColorScheme() ? 'dark' : 'light';
|
|
28
|
+
}
|
|
29
|
+
// An override outlives a reload only while the OS still disagrees with it; one
|
|
30
|
+
// the OS has since come round to means following again.
|
|
31
|
+
function storedOverride() {
|
|
32
|
+
const stored = localStorageGetItem('themeModeOverride');
|
|
33
|
+
return (stored === 'light' || stored === 'dark') && stored !== systemMode()
|
|
34
|
+
? stored
|
|
35
|
+
: undefined;
|
|
36
|
+
}
|
|
37
|
+
// A `themeName` stored before light and dark were an axis spells a mode into
|
|
38
|
+
// the name. Split it once, on the way in, so the session persists the pair from
|
|
39
|
+
// then on and the retired name goes away; a name this does not know — an
|
|
40
|
+
// `extraThemes` entry whose plugin is absent — passes through untouched.
|
|
41
|
+
function storedSelection() {
|
|
42
|
+
const stored = localStorageGetItem('themeName') ?? 'default';
|
|
43
|
+
const { themeName, mode } = resolveThemeSelection(stored);
|
|
44
|
+
const storedMode = localStorageGetItem('themeMode');
|
|
45
|
+
return {
|
|
46
|
+
sessionThemeName: themeName,
|
|
47
|
+
sessionThemeMode: storedMode ?? mode ?? DEFAULT_MODE,
|
|
48
|
+
systemThemeOverride: storedOverride(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The theme the stored selection resolves to, for UI drawn before a session
|
|
53
|
+
* exists, such as Desktop's start screen.
|
|
54
|
+
*/
|
|
55
|
+
export function storedThemeArgs() {
|
|
56
|
+
const { sessionThemeName, sessionThemeMode, systemThemeOverride } = storedSelection();
|
|
57
|
+
return {
|
|
58
|
+
themeName: sessionThemeName,
|
|
59
|
+
mode: sessionThemeMode === 'system'
|
|
60
|
+
? (systemThemeOverride ?? systemMode())
|
|
61
|
+
: sessionThemeMode,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* #stateModel ThemeManagerSessionMixin
|
|
66
|
+
*/
|
|
6
67
|
export function ThemeManagerSessionMixin(_pluginManager) {
|
|
7
68
|
return types
|
|
8
69
|
.model({})
|
|
9
70
|
.volatile(() => ({
|
|
10
|
-
|
|
71
|
+
...storedSelection(),
|
|
72
|
+
systemPrefersDark: prefersDarkColorScheme(),
|
|
11
73
|
}))
|
|
12
|
-
.views(s =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
74
|
+
.views(s => {
|
|
75
|
+
const self = asSession(s);
|
|
76
|
+
return {
|
|
77
|
+
/**
|
|
78
|
+
* #method
|
|
79
|
+
*/
|
|
80
|
+
allThemes() {
|
|
81
|
+
const extraThemes = getConf(self.jbrowse, 'extraThemes');
|
|
82
|
+
return { ...defaultThemes, ...extraThemes };
|
|
83
|
+
},
|
|
84
|
+
/**
|
|
85
|
+
* #getter
|
|
86
|
+
* Which palette is in effect. A stored name whose theme an admin has
|
|
87
|
+
* since dropped reads as `default` without the stored value being
|
|
88
|
+
* touched, so it comes back if the plugin supplying it loads again.
|
|
89
|
+
*/
|
|
90
|
+
get themeName() {
|
|
91
|
+
return resolveThemeName(this.allThemes(), self.sessionThemeName);
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* #getter
|
|
95
|
+
* Light, dark, or following the OS — the axis the palette is drawn
|
|
96
|
+
* along, and what the mode picker shows. `effectiveThemeMode` is the
|
|
97
|
+
* one to read for a colour decision.
|
|
98
|
+
*/
|
|
99
|
+
get themeMode() {
|
|
100
|
+
return self.sessionThemeMode;
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* #getter
|
|
104
|
+
* Light or dark, with `system` resolved against the OS preference or
|
|
105
|
+
* the toolbar's hold on the other mode.
|
|
106
|
+
*/
|
|
107
|
+
get effectiveThemeMode() {
|
|
108
|
+
return this.themeMode === 'system'
|
|
109
|
+
? (self.systemThemeOverride ??
|
|
110
|
+
(self.systemPrefersDark ? 'dark' : 'light'))
|
|
111
|
+
: this.themeMode;
|
|
112
|
+
},
|
|
113
|
+
/**
|
|
114
|
+
* #getter
|
|
115
|
+
* Whether what is drawn right now is dark. Read off the resolved
|
|
116
|
+
* palette rather than the mode, so a palette pinned to one mode — an
|
|
117
|
+
* `extraThemes` entry declaring `mode: 'dark'` — answers for itself.
|
|
118
|
+
*/
|
|
119
|
+
get themeIsDark() {
|
|
120
|
+
return this.palette.mode === 'dark';
|
|
121
|
+
},
|
|
122
|
+
/**
|
|
123
|
+
* #getter
|
|
124
|
+
*/
|
|
125
|
+
// Structurally-serializable description of the active theme, safe to
|
|
126
|
+
// send across the RPC worker boundary (the created `theme` carries
|
|
127
|
+
// functions and cannot be cloned). The worker rebuilds via
|
|
128
|
+
// createJBrowseThemeFromArgs.
|
|
129
|
+
get themeOptions() {
|
|
130
|
+
return {
|
|
131
|
+
configTheme: getConf(self.jbrowse, 'theme'),
|
|
132
|
+
extraThemes: getConf(self.jbrowse, 'extraThemes'),
|
|
133
|
+
themeName: this.themeName,
|
|
134
|
+
mode: this.effectiveThemeMode,
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
/**
|
|
138
|
+
* #getter
|
|
139
|
+
* Every color JBrowse renders, resolved to plain strings. This is what
|
|
140
|
+
* rendering reads: it needs no React context, it crosses the RPC worker
|
|
141
|
+
* boundary as itself, and it costs no UI toolkit. Prefer it over
|
|
142
|
+
* `theme` anywhere the answer wanted is a color rather than a Material
|
|
143
|
+
* UI component style.
|
|
144
|
+
*/
|
|
145
|
+
get palette() {
|
|
146
|
+
return resolvePalette(this.themeOptions);
|
|
147
|
+
},
|
|
148
|
+
/**
|
|
149
|
+
* #getter
|
|
150
|
+
* The palette plus the sizing tokens `makeStyles` reads — spacing,
|
|
151
|
+
* corner radius, type scale. This is what a product mounts on
|
|
152
|
+
* `StyleThemeProvider`; it costs no UI toolkit, and it is derived from
|
|
153
|
+
* the same `themeOptions` as `theme`, so a config `theme` that sets
|
|
154
|
+
* `spacing` moves JBrowse's own styles and its Material components
|
|
155
|
+
* together.
|
|
156
|
+
*/
|
|
157
|
+
get styleTheme() {
|
|
158
|
+
return resolveStyleTheme(this.themeOptions);
|
|
159
|
+
},
|
|
160
|
+
/**
|
|
161
|
+
* #getter
|
|
162
|
+
* The Material UI theme, for the components that are Material UI. Its
|
|
163
|
+
* palette is spliced from the same `resolvePalette` call as `palette`
|
|
164
|
+
* above, so the two cannot disagree.
|
|
165
|
+
*/
|
|
166
|
+
get theme() {
|
|
167
|
+
return createJBrowseThemeFromArgs(this.themeOptions);
|
|
168
|
+
},
|
|
169
|
+
/**
|
|
170
|
+
* #method
|
|
171
|
+
* Raw `ThemeOptions` for the active theme, or a named override (used by
|
|
172
|
+
* the SVG-export theme picker). Unlike `theme` (a built,
|
|
173
|
+
* non-serializable MUI theme), this is the plain options object every
|
|
174
|
+
* view's SVG export threads into each display's `renderSvg`, which
|
|
175
|
+
* rebuilds the theme via `createJBrowseTheme` outside React context.
|
|
176
|
+
*
|
|
177
|
+
* The `default` entry is merged with the config `theme` slot, because
|
|
178
|
+
* the picker labels it "Default (from config)" and `resolvePalette`
|
|
179
|
+
* merges the preset with the slot for every other consumer. The bare
|
|
180
|
+
* preset would make `view.exportSvg()` drop a host's configured
|
|
181
|
+
* palette: a config setting `primary.main` would draw `#123456` on
|
|
182
|
+
* screen and export the stock `#0D233F`, while the export dialog named
|
|
183
|
+
* the default theme. Every other named theme is a fixed preset that
|
|
184
|
+
* ignores config.
|
|
185
|
+
*
|
|
186
|
+
* **The mode is spliced in here**, because a palette no longer carries
|
|
187
|
+
* one and this is the last point before the export leaves the session:
|
|
188
|
+
* every caller hands `renderSvg` these options and nothing else, so a
|
|
189
|
+
* figure exported from a dark session comes out dark. A palette pinned
|
|
190
|
+
* to its own mode, or a `name` from before the axis, states the mode
|
|
191
|
+
* itself and keeps it.
|
|
192
|
+
*/
|
|
193
|
+
getActiveThemeOptions(name) {
|
|
194
|
+
const all = this.allThemes();
|
|
195
|
+
const selection = resolveThemeSelection(name ?? this.themeName, undefined, all);
|
|
196
|
+
const themeName = resolveThemeName(all, selection.themeName);
|
|
197
|
+
const theme = all[themeName];
|
|
198
|
+
const mode = theme?.palette?.mode ?? selection.mode ?? this.effectiveThemeMode;
|
|
199
|
+
if (themeName !== 'default') {
|
|
200
|
+
return { ...theme, palette: { ...theme?.palette, mode } };
|
|
201
|
+
}
|
|
202
|
+
// shallow over the palette, which is how `resolvePalette` spreads the
|
|
203
|
+
// same two — `mode` and `primary` are siblings there, so both levels
|
|
204
|
+
// have to survive
|
|
205
|
+
const configTheme = getConf(self.jbrowse, 'theme');
|
|
206
|
+
return {
|
|
207
|
+
...theme,
|
|
208
|
+
...configTheme,
|
|
209
|
+
palette: { ...theme?.palette, ...configTheme.palette, mode },
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
})
|
|
214
|
+
.actions(self => ({
|
|
215
|
+
/**
|
|
216
|
+
* #action
|
|
217
|
+
* Pick a palette. A name from before light and dark were an axis sets
|
|
218
|
+
* the mode it spelled as well, so an old share link, a saved figure spec
|
|
219
|
+
* and `jbrowse-img --theme darkStock` all still mean what they said.
|
|
220
|
+
* Either that or a palette pinned to its own mode drops a held mode,
|
|
221
|
+
* which would otherwise resurface on the next palette change.
|
|
222
|
+
*/
|
|
223
|
+
setThemeName(name) {
|
|
224
|
+
const { themeName, mode } = resolveThemeSelection(name);
|
|
225
|
+
self.sessionThemeName = themeName;
|
|
226
|
+
if (mode) {
|
|
227
|
+
self.sessionThemeMode = mode;
|
|
228
|
+
}
|
|
229
|
+
const drawnMode = self.themeIsDark ? 'dark' : 'light';
|
|
230
|
+
if (mode || drawnMode !== self.effectiveThemeMode) {
|
|
231
|
+
self.systemThemeOverride = undefined;
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
/**
|
|
235
|
+
* #action
|
|
236
|
+
*/
|
|
237
|
+
setSystemPrefersDark(dark) {
|
|
238
|
+
if (dark !== self.systemPrefersDark) {
|
|
239
|
+
self.systemThemeOverride = undefined;
|
|
240
|
+
}
|
|
241
|
+
self.systemPrefersDark = dark;
|
|
17
242
|
},
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
243
|
+
/**
|
|
244
|
+
* #action
|
|
245
|
+
* Hold a session that follows the system on the mode the OS is not
|
|
246
|
+
* asking for, or `undefined` to follow it again. The toolbar's sun/moon
|
|
247
|
+
* writes this, so it stays in the toolbar after a click. The OS flipping
|
|
248
|
+
* clears it, since by then the OS has come round to the held mode. The
|
|
249
|
+
* palette is untouched: a reader on Minimal who does this keeps Minimal.
|
|
250
|
+
*/
|
|
251
|
+
setSystemThemeOverride(mode) {
|
|
252
|
+
self.systemThemeOverride = mode;
|
|
22
253
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
254
|
+
/**
|
|
255
|
+
* #action
|
|
256
|
+
* Draw the session light or dark, leaving the palette alone. `system`
|
|
257
|
+
* follows the OS preference. Satisfies `ThemeModeSession`, so
|
|
258
|
+
* `useSessionPalette` works against an app session and an embedded one
|
|
259
|
+
* alike, and a host that follows its own dark-mode state calls this.
|
|
260
|
+
*
|
|
261
|
+
* `themeOptions` carries the mode to the RPC worker, so the labels baked
|
|
262
|
+
* into a rendered image follow it along with what React draws. That used
|
|
263
|
+
* to take a write into the config `theme` slot, because mode lived
|
|
264
|
+
* inside a palette and there was nowhere else to put it.
|
|
265
|
+
*/
|
|
266
|
+
setThemeMode(mode) {
|
|
267
|
+
self.sessionThemeMode = mode;
|
|
268
|
+
self.systemThemeOverride = undefined;
|
|
28
269
|
},
|
|
29
270
|
}))
|
|
30
271
|
.actions(self => ({
|
|
31
|
-
setThemeName(name) {
|
|
32
|
-
self.sessionThemeName = name;
|
|
33
|
-
},
|
|
34
272
|
afterAttach() {
|
|
273
|
+
addDisposer(self, onColorSchemeChange(() => {
|
|
274
|
+
self.setSystemPrefersDark(prefersDarkColorScheme());
|
|
275
|
+
}));
|
|
35
276
|
addDisposer(self, autorun(function themeNameAutorun() {
|
|
36
|
-
|
|
277
|
+
// persist the raw selection, not the coerced themeName, so a
|
|
278
|
+
// theme registered later isn't clobbered with 'default'
|
|
279
|
+
localStorageSetItem('themeName', self.sessionThemeName);
|
|
280
|
+
localStorageSetItem('themeMode', self.sessionThemeMode);
|
|
281
|
+
localStorageSetItem('themeModeOverride', self.systemThemeOverride ?? '');
|
|
37
282
|
}, { name: 'ThemeName' }));
|
|
38
283
|
},
|
|
39
284
|
}));
|
|
40
285
|
}
|
|
286
|
+
/** Type guard for SessionWithThemes */
|
|
41
287
|
export function isSessionWithThemes(session) {
|
|
42
|
-
return 'theme' in session;
|
|
288
|
+
return isBaseSession(session) && 'theme' in session;
|
|
43
289
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type PluginManager from '@jbrowse/core/PluginManager';
|
|
2
|
+
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
3
|
+
import type { BaseTrackConfig } from '@jbrowse/core/pluggableElementTypes';
|
|
4
|
+
import type { MenuItem } from '@jbrowse/core/ui';
|
|
5
|
+
import type { DialogComponentType } from '@jbrowse/core/util';
|
|
6
|
+
import type { TrackActionView } from '@jbrowse/core/util/types';
|
|
7
|
+
interface TrackActionSession<C> {
|
|
8
|
+
editConfiguration: (config: AnyConfigurationModel | {
|
|
9
|
+
trackId: string;
|
|
10
|
+
}, opts?: {
|
|
11
|
+
expandedDisplayId?: string;
|
|
12
|
+
}) => void;
|
|
13
|
+
publishTrackConf: (conf: C) => unknown;
|
|
14
|
+
deleteTrackConf: (conf: AnyConfigurationModel) => void;
|
|
15
|
+
resetTrackConfiguration?: (trackId: string) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Declared here, though only the copy guard below reads it, so a session that
|
|
18
|
+
* loses the list loses the guard *loudly*. `namesTemporaryAssembly` takes an
|
|
19
|
+
* `unknown` session and answers false for one that holds no such list, which
|
|
20
|
+
* is right for a caller that genuinely has none and wrong for one that let it
|
|
21
|
+
* drop — and that second case is a copy action silently offered again.
|
|
22
|
+
*
|
|
23
|
+
* `unknown[]`, the spelling `AbstractSessionModel` already uses, and not the
|
|
24
|
+
* `{ name?: string }[]` the guard narrows to: that one is a weak type, so a
|
|
25
|
+
* real MST array of assembly configs — whose element type is an index
|
|
26
|
+
* signature that declares no `name` — shares no property with it and TS
|
|
27
|
+
* rejects the assignment. The shape belongs in the guard, which is the only
|
|
28
|
+
* thing that reads it.
|
|
29
|
+
*/
|
|
30
|
+
temporaryAssemblies?: unknown[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The shared Settings / Copy / Copy-and-open / Delete track actions. Each
|
|
34
|
+
* product supplies `makeCopy` (its own session-track/category rules) and
|
|
35
|
+
* `canEdit`; reference sequence tracks can't be copied or deleted. When
|
|
36
|
+
* `isSessionOverride` is set the track carries session edits over its base
|
|
37
|
+
* config, so a Reset is offered, and it replaces Delete for a user who cannot
|
|
38
|
+
* delete the base.
|
|
39
|
+
*/
|
|
40
|
+
export declare function trackActionItems<C extends {
|
|
41
|
+
trackId: string;
|
|
42
|
+
}>({ session, config, view, canEdit, isSessionOverride, makeCopy, }: {
|
|
43
|
+
session: TrackActionSession<C>;
|
|
44
|
+
config: BaseTrackConfig;
|
|
45
|
+
view?: TrackActionView;
|
|
46
|
+
canEdit: boolean;
|
|
47
|
+
isSessionOverride?: boolean;
|
|
48
|
+
makeCopy: () => C;
|
|
49
|
+
}): MenuItem[];
|
|
50
|
+
export interface SessionWithDialog {
|
|
51
|
+
queueDialog: (cb: (done: () => void) => [DialogComponentType, Record<string, unknown>]) => void;
|
|
52
|
+
}
|
|
53
|
+
type TrackConfig = AnyConfigurationModel | Record<string, unknown>;
|
|
54
|
+
/** "About track" menu item, shared by every product's track menu */
|
|
55
|
+
export declare function aboutTrackMenuItem(session: SessionWithDialog, config: TrackConfig): MenuItem;
|
|
56
|
+
/**
|
|
57
|
+
* flattened track menu (About + raw actions) for the hierarchical track selector
|
|
58
|
+
*/
|
|
59
|
+
export declare function trackListMenuItems(session: SessionWithDialog, config: TrackConfig, actions: MenuItem[]): MenuItem[];
|
|
60
|
+
/**
|
|
61
|
+
* track menu with an "About track" item and a "Track actions" submenu, for the
|
|
62
|
+
* in-view track label menu
|
|
63
|
+
*/
|
|
64
|
+
export declare function trackActionMenuItems(session: SessionWithDialog, config: TrackConfig, actions: MenuItem[]): MenuItem[];
|
|
65
|
+
/**
|
|
66
|
+
* #stateModel TrackMenuItemsSessionMixin
|
|
67
|
+
*
|
|
68
|
+
* The two track-menu wrappers (`getTrackListMenuItems` for the hierarchical
|
|
69
|
+
* selector, `getTrackActionMenuItems` for the in-view label menu) shared by the
|
|
70
|
+
* full web and desktop sessions. Both are pure functions of `getTrackActions`,
|
|
71
|
+
* which each session supplies (web gates on edit rights; desktop adds indexing).
|
|
72
|
+
*/
|
|
73
|
+
export declare function TrackMenuItemsSessionMixin(pluginManager: PluginManager): import("@jbrowse/mobx-state-tree").IModelType<{}, {
|
|
74
|
+
/**
|
|
75
|
+
* #method
|
|
76
|
+
* flattened menu items for use in hierarchical track selector
|
|
77
|
+
*/
|
|
78
|
+
getTrackListMenuItems(config: BaseTrackConfig, view?: TrackActionView): MenuItem[];
|
|
79
|
+
/**
|
|
80
|
+
* #method
|
|
81
|
+
* track menu with About + "Track actions" submenu for the in-view label
|
|
82
|
+
*/
|
|
83
|
+
getTrackActionMenuItems({ config, view, }: {
|
|
84
|
+
config: BaseTrackConfig;
|
|
85
|
+
view?: TrackActionView;
|
|
86
|
+
}): MenuItem[];
|
|
87
|
+
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
88
|
+
export {};
|