@jbrowse/core 5.0.0-beta.2 → 5.0.0-beta.3
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/README.md +70 -40
- package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +2 -3
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.d.ts +4 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.js +17 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +4 -3
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.d.ts +2 -2
- package/esm/BaseFeatureWidget/index.d.ts +1 -1
- package/esm/BaseFeatureWidget/stateModelFactory.d.ts +8 -1
- package/esm/BaseFeatureWidget/stateModelFactory.js +6 -0
- package/esm/BaseFeatureWidget/types.d.ts +10 -2
- package/esm/PluginManager.d.ts +30 -1
- package/esm/PluginManager.js +107 -70
- package/esm/ReExports/BaseFeatureDetails.js +1 -1
- package/esm/ReExports/MuiDataGridReExports.d.ts +1 -0
- package/esm/ReExports/MuiDataGridReExports.js +2 -2
- package/esm/ReExports/barrelOnlyNames.d.ts +5 -0
- package/esm/ReExports/barrelOnlyNames.js +63 -0
- package/esm/ReExports/modules.js +28 -56
- package/esm/ReExports/publicTracks.d.ts +1 -0
- package/esm/ReExports/publicTracks.js +14 -0
- package/esm/ReExports/publicUi.d.ts +4 -0
- package/esm/ReExports/publicUi.js +33 -0
- package/esm/ReExports/publicUtil.d.ts +1 -1
- package/esm/ReExports/publicUtil.js +8 -4
- package/esm/ReExports/sharedModules.d.ts +1 -1
- package/esm/ReExports/sharedModules.js +8 -1
- package/esm/ReExports/uiStub.d.ts +1 -0
- package/esm/ReExports/uiStub.js +6 -8
- package/esm/ReExports/workerModules.js +9 -4
- package/esm/ReExports/workerNamespaceNames.d.ts +11 -0
- package/esm/ReExports/workerNamespaceNames.js +281 -0
- package/esm/configuration/configurationSchema.js +11 -0
- package/esm/configuration/index.d.ts +2 -2
- package/esm/configuration/index.js +1 -1
- package/esm/configuration/promotableDefaults.d.ts +54 -19
- package/esm/configuration/promotableDefaults.js +108 -45
- package/esm/configuration/promotablePin.d.ts +50 -40
- package/esm/configuration/promotableResolve.d.ts +1 -1
- package/esm/configuration/promotableResolve.js +1 -1
- package/esm/configuration/tabixIndexFields.d.ts +2 -2
- package/esm/configuration/tabixIndexFields.js +2 -2
- package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +4 -12
- package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +12 -0
- package/esm/data_adapters/BaseAdapter/featureDensity.js +15 -0
- package/esm/data_adapters/BaseAdapter/index.d.ts +2 -2
- package/esm/data_adapters/BaseAdapter/index.js +1 -1
- package/esm/data_adapters/BaseAdapter/types.d.ts +2 -8
- package/esm/pluggableElementTypes/AdapterType.d.ts +2 -1
- package/esm/pluggableElementTypes/AdapterType.js +1 -1
- package/esm/pluggableElementTypes/DisplayType.d.ts +3 -10
- package/esm/pluggableElementTypes/DisplayType.js +3 -45
- package/esm/pluggableElementTypes/LazyStateModelElement.d.ts +27 -0
- package/esm/pluggableElementTypes/LazyStateModelElement.js +71 -0
- package/esm/pluggableElementTypes/ViewType.d.ts +3 -10
- package/esm/pluggableElementTypes/ViewType.js +6 -51
- package/esm/pluggableElementTypes/extendElementType.d.ts +1 -2
- package/esm/pluggableElementTypes/extendElementType.js +1 -2
- package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +3 -3
- package/esm/pluggableElementTypes/models/BaseDisplayModel.js +1 -1
- package/esm/pluggableElementTypes/models/BaseTrackModel.js +1 -4
- package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +34 -34
- package/esm/pluggableElementTypes/models/BaseViewModel.js +19 -30
- package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +4 -3
- package/esm/pluggableElementTypes/models/assertDisplayContract.js +2 -2
- package/esm/pluggableElementTypes/models/baseTrackConfig.js +7 -1
- package/esm/ui/BaseExportSvgDialog.d.ts +1 -1
- package/esm/ui/ErrorMessageStackTraceDialog.js +5 -6
- package/esm/ui/ExportSvgDialog.d.ts +1 -1
- package/esm/ui/MenuTypes.d.ts +3 -3
- package/esm/ui/PinAdornment.js +22 -40
- package/esm/ui/ScrollChrome.d.ts +16 -0
- package/esm/ui/ScrollChrome.js +12 -0
- package/esm/ui/ScrollZoomToggle.d.ts +4 -3
- package/esm/ui/ScrollZoomToggle.js +4 -3
- package/esm/ui/SizeSliderRow.js +1 -1
- package/esm/ui/index.d.ts +2 -2
- package/esm/ui/index.js +3 -3
- package/esm/ui/legendMenuItem.d.ts +9 -15
- package/esm/ui/legendMenuItem.js +8 -19
- package/esm/ui/menuItemAdornment.d.ts +2 -3
- package/esm/ui/menuItemAdornment.js +2 -3
- package/esm/ui/menuItems.d.ts +1 -2
- package/esm/ui/menuItems.js +0 -1
- package/esm/ui/palette.d.ts +11 -11
- package/esm/ui/palette.js +11 -11
- package/esm/ui/promotablePinCoverage.d.ts +16 -2
- package/esm/ui/promotablePinCoverage.js +38 -2
- package/esm/ui/theme.js +5 -0
- package/esm/ui/toggleMenuItems.d.ts +13 -6
- package/esm/ui/toggleMenuItems.js +32 -15
- package/esm/util/Base1DUtils.d.ts +4 -2
- package/esm/util/Base1DUtils.js +12 -4
- package/esm/util/SvgCanvas.js +4 -3
- package/esm/util/adapterConfigKey.d.ts +12 -0
- package/esm/util/adapterConfigKey.js +14 -0
- package/esm/util/adapterMetadata.js +2 -1
- package/esm/util/analytics.js +4 -5
- package/esm/util/clampToContig.d.ts +17 -0
- package/esm/util/clampToContig.js +19 -0
- package/esm/util/colorBits.d.ts +2 -1
- package/esm/util/colorBits.js +2 -5
- package/esm/util/createStopTokenRotation.d.ts +8 -7
- package/esm/util/featureTypes.d.ts +24 -0
- package/esm/util/featureTypes.js +35 -0
- package/esm/util/fetchPhases.d.ts +1 -1
- package/esm/util/index.d.ts +4 -2
- package/esm/util/index.js +3 -1
- package/esm/util/installFetch.d.ts +29 -18
- package/esm/util/installFetch.js +17 -17
- package/esm/util/installInitAutorun.d.ts +6 -5
- package/esm/util/installInitAutorun.js +2 -2
- package/esm/util/installPrerequisiteFetch.d.ts +86 -0
- package/esm/util/installPrerequisiteFetch.js +73 -0
- package/esm/util/openFeatureWidget.d.ts +5 -0
- package/esm/util/openFeatureWidget.js +1 -0
- package/esm/util/openViews.d.ts +16 -0
- package/esm/util/openViews.js +22 -0
- package/esm/util/parentWalk.d.ts +1 -1
- package/esm/util/parentWalk.js +1 -1
- package/esm/util/renderToStaticMarkup.js +10 -0
- package/esm/util/scheduleDetachedDestroy.d.ts +18 -0
- package/esm/util/scheduleDetachedDestroy.js +24 -0
- package/esm/util/scrollLatch.d.ts +1 -0
- package/esm/util/scrollLatch.js +8 -0
- package/esm/util/stopToken.d.ts +6 -5
- package/esm/util/trackConfigDelta.d.ts +6 -6
- package/esm/util/trackConfigDelta.js +3 -3
- package/esm/util/types/index.d.ts +25 -20
- package/esm/util/usePanelVirtualScroll.d.ts +6 -2
- package/esm/util/usePanelVirtualScroll.js +6 -2
- package/esm/util/useRowVirtualScroll.d.ts +1 -1
- package/esm/util/useRowVirtualScroll.js +1 -1
- package/esm/util/useVirtualScrollWheel.js +11 -1
- package/esm/util/wheelZoom.d.ts +3 -1
- package/esm/util/wheelZoom.js +39 -14
- package/esm/util/withLaunchInput.d.ts +47 -2
- package/esm/util/withLaunchInput.js +56 -11
- package/package.json +10 -5
- package/esm/ui/promotableMenuItems.d.ts +0 -19
- package/esm/ui/promotableMenuItems.js +0 -91
|
@@ -1,55 +1,65 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* the trailing `PushPin`, bundled so the row consumes it as one prop. Built by
|
|
5
|
-
* {@link makePin}.
|
|
2
|
+
* Shared by both pin kinds: which promotable slot the pin writes, whether it
|
|
3
|
+
* draws filled, and the one click it takes.
|
|
6
4
|
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* the
|
|
11
|
-
*
|
|
5
|
+
* `slot` is here so a *built menu* can be asked which promotable slots it offers
|
|
6
|
+
* a pin for, which is the only way that question has an answer: declaring
|
|
7
|
+
* `promotedBase` is a schema fact and the pin is a menu fact, and a display that
|
|
8
|
+
* inherits the slot but never builds a row has a slot nothing can ever promote,
|
|
9
|
+
* silently (`promotableSlotsWithoutPin`, guarded by
|
|
10
|
+
* `products/jbrowse-web/src/tests/PromotablePinCoverage.test.ts`).
|
|
12
11
|
*
|
|
13
12
|
* **`toggle` rather than an `apply`/`clear` pair**, which was tried and dropped:
|
|
14
13
|
* the sole renderer is a MUI `ToggleButton` whose `onChange` means exactly
|
|
15
14
|
* "flip", so splitting it adds a member *and* a branch at the one call site that
|
|
16
|
-
* never needed one. `active` is already public for a caller that wants to state
|
|
17
|
-
* direction.
|
|
18
|
-
* actions, where a toggle destroys the ability to set a known state; nothing here
|
|
19
|
-
* stores a value.)
|
|
15
|
+
* never needed one. `active` is already public for a caller that wants to state
|
|
16
|
+
* a direction.
|
|
20
17
|
*
|
|
21
18
|
* Lives here, alone and with no imports, rather than beside `makePin` in
|
|
22
19
|
* `promotableDefaults.ts`: the menu types describe a pin without building one,
|
|
23
|
-
* and `MenuTypes.ts` taking this
|
|
24
|
-
*
|
|
25
|
-
*
|
|
20
|
+
* and `MenuTypes.ts` taking this from that module gave a React-free type file a
|
|
21
|
+
* type closure of 374 files. See `agent-docs/ideas/barrels-block-extraction.md`
|
|
22
|
+
* and `scripts/moduleClosure.ts`.
|
|
26
23
|
*/
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The promotable slot this pin promotes a value of. Nothing in the UI reads
|
|
30
|
-
* it — a pin renders from `active`, `onValue` and the toggle. It is here so a
|
|
31
|
-
* *built menu* can be asked which promotable slots it offers a pin for, which
|
|
32
|
-
* is the only way that question has an answer: declaring `promotedBase` is a
|
|
33
|
-
* schema fact and the pin is a menu fact, and a display that inherits the slot
|
|
34
|
-
* but never builds a row has a slot nothing can ever promote, silently
|
|
35
|
-
* (`promotableSlotsWithoutPin`, guarded by
|
|
36
|
-
* `products/jbrowse-web/src/tests/PromotablePinCoverage.test.ts`).
|
|
37
|
-
*/
|
|
24
|
+
interface PinBase {
|
|
38
25
|
slot: string;
|
|
39
|
-
/**
|
|
40
|
-
* The value `toggle` promotes — the on-value {@link makePin} was given, or the
|
|
41
|
-
* track's current resolved value for the value-omitted form.
|
|
42
|
-
*
|
|
43
|
-
* `PinAdornment` words itself from this, and has to: a **boolean** on-value
|
|
44
|
-
* promotes a *state*, so a row whose label names the setting rather than a
|
|
45
|
-
* value ("Show legend") gets a pin that promotes hiding the legend as often as
|
|
46
|
-
* showing it. Every other on-value IS what the row's label says — a radio
|
|
47
|
-
* option, a slider's current size — so those keep the value-shaped copy.
|
|
48
|
-
*
|
|
49
|
-
* Required, like `slot`: a pin that cannot say what it promotes is what let
|
|
50
|
-
* that copy state the opposite of what the click does.
|
|
51
|
-
*/
|
|
26
|
+
/** what `toggle` writes into every open track of the display type */
|
|
52
27
|
onValue: unknown;
|
|
53
28
|
active: boolean;
|
|
54
29
|
toggle: () => void;
|
|
55
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* #api core/configuration
|
|
33
|
+
* The pin on a radio or slider row, built by {@link makePin}: `onValue` is the
|
|
34
|
+
* row's own value, `active` means that value is the display type's promoted
|
|
35
|
+
* default, and `toggle` on an outline pin applies the value to every open track
|
|
36
|
+
* and offers it as the default, while on a filled pin it clears that default
|
|
37
|
+
* and touches no track (`applyAndOfferDefault` / `clearDefault`).
|
|
38
|
+
*/
|
|
39
|
+
export interface ValuePin extends PinBase {
|
|
40
|
+
kind: 'value';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* #api core/configuration
|
|
44
|
+
* The pin on a checkbox row, built by {@link makeTogglePin}: the row's own
|
|
45
|
+
* checkbox over every open track of the display type. `active` mirrors the row,
|
|
46
|
+
* `onValue` is the state a click applies (the row's opposite), and `toggle`
|
|
47
|
+
* applies it everywhere and offers it as the default. It never clears a default
|
|
48
|
+
* on its own — promoting the slot's base value is what clears one.
|
|
49
|
+
*/
|
|
50
|
+
export interface TogglePin extends PinBase {
|
|
51
|
+
kind: 'toggle';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* #api core/configuration
|
|
55
|
+
* The "apply this to every open track of this type" affordance on a menu row —
|
|
56
|
+
* the trailing `PushPin`, bundled so the row consumes it as one prop.
|
|
57
|
+
*
|
|
58
|
+
* `kind` is what the adornment words itself from and what the row builders
|
|
59
|
+
* check: a checkbox row takes a {@link TogglePin}, a radio or slider row a
|
|
60
|
+
* {@link ValuePin}. The two used to be told apart by `typeof onValue ===
|
|
61
|
+
* 'boolean'`, which let a value pin over a boolean slot compile and read as a
|
|
62
|
+
* toggle while clearing on its second click.
|
|
63
|
+
*/
|
|
64
|
+
export type Pin = ValuePin | TogglePin;
|
|
65
|
+
export {};
|
|
@@ -69,7 +69,7 @@ export declare function storedSlotValue(config: AnyConfigurationModel, slot: str
|
|
|
69
69
|
* about a value a caller is about to offer as a pin's on-value.
|
|
70
70
|
*
|
|
71
71
|
* Exists because a pin built over a value the gate refuses is inert in a way
|
|
72
|
-
* nothing reports: `
|
|
72
|
+
* nothing reports: `applyAndOfferDefault` writes it to the session store happily,
|
|
73
73
|
* `resolveSlotIn` then drops it and every track keeps resolving to the tier
|
|
74
74
|
* below, and `isPromotableDefault` compares the *raw* stored value, so the pin
|
|
75
75
|
* draws outline forever while a dead key sits in the user's localStorage. See
|
|
@@ -51,7 +51,7 @@ export function storedSlotValue(config, slot) {
|
|
|
51
51
|
* about a value a caller is about to offer as a pin's on-value.
|
|
52
52
|
*
|
|
53
53
|
* Exists because a pin built over a value the gate refuses is inert in a way
|
|
54
|
-
* nothing reports: `
|
|
54
|
+
* nothing reports: `applyAndOfferDefault` writes it to the session store happily,
|
|
55
55
|
* `resolveSlotIn` then drops it and every track keeps resolving to the tier
|
|
56
56
|
* below, and `isPromotableDefault` compares the *raw* stored value, so the pin
|
|
57
57
|
* draws outline forever while a dead key sits in the user's localStorage. See
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* two slots in the opposite order
|
|
15
15
|
* - `PairwiseIndexedPAFAdapter`'s prose said `<file>.pif.gz.tbi` while its
|
|
16
16
|
* default said `my.paf.gz.tbi`
|
|
17
|
-
* - `PlinkLDTabixAdapter` dropped the
|
|
17
|
+
* - `PlinkLDTabixAdapter`'s description dropped a clause the other eight carried
|
|
18
18
|
* - the placeholder extensions disagreed with each other for no reason
|
|
19
19
|
*
|
|
20
20
|
* The description is written for every tabix adapter rather than naming one
|
|
@@ -39,6 +39,6 @@ export declare const tabixIndexFields: {
|
|
|
39
39
|
readonly uri: '/path/to/my.gz.tbi';
|
|
40
40
|
readonly locationType: 'UriLocation';
|
|
41
41
|
};
|
|
42
|
-
readonly description: 'location of the tabix index. Only needed when it is not named `<file>.tbi`
|
|
42
|
+
readonly description: 'location of the tabix index. Only needed when it is not named `<file>.tbi`, which is what the `uri` shorthand assumes — a `.csi` beside the file is reached with `csi: true` rather than by spelling this out.';
|
|
43
43
|
};
|
|
44
44
|
};
|
|
@@ -15,7 +15,7 @@ import { types } from '@jbrowse/mobx-state-tree';
|
|
|
15
15
|
* two slots in the opposite order
|
|
16
16
|
* - `PairwiseIndexedPAFAdapter`'s prose said `<file>.pif.gz.tbi` while its
|
|
17
17
|
* default said `my.paf.gz.tbi`
|
|
18
|
-
* - `PlinkLDTabixAdapter` dropped the
|
|
18
|
+
* - `PlinkLDTabixAdapter`'s description dropped a clause the other eight carried
|
|
19
19
|
* - the placeholder extensions disagreed with each other for no reason
|
|
20
20
|
*
|
|
21
21
|
* The description is written for every tabix adapter rather than naming one
|
|
@@ -40,6 +40,6 @@ export const tabixIndexFields = {
|
|
|
40
40
|
uri: '/path/to/my.gz.tbi',
|
|
41
41
|
locationType: 'UriLocation',
|
|
42
42
|
},
|
|
43
|
-
description: 'location of the tabix index. Only needed when it is not named `<file>.tbi`
|
|
43
|
+
description: 'location of the tabix index. Only needed when it is not named `<file>.tbi`, which is what the `uri` shorthand assumes — a `.csi` beside the file is reached with `csi: true` rather than by spelling this out.',
|
|
44
44
|
},
|
|
45
45
|
};
|
|
@@ -3,14 +3,9 @@ import { toArray } from 'rxjs/operators';
|
|
|
3
3
|
import { createStatusFanOut } from '../../util/progress.js';
|
|
4
4
|
import { blankStats, scoresToStats } from '../../util/stats.js';
|
|
5
5
|
import { BaseAdapter } from './BaseAdapter.js';
|
|
6
|
+
import { isSubAdapterConfig } from './featureDensity.js';
|
|
6
7
|
import { aggregateQuantitativeStats } from './stats.js';
|
|
7
8
|
import { isFeatureAdapter } from './util.js';
|
|
8
|
-
function isAdapterConfigSnapshot(value) {
|
|
9
|
-
return (typeof value === 'object' &&
|
|
10
|
-
value !== null &&
|
|
11
|
-
'type' in value &&
|
|
12
|
-
typeof value.type === 'string');
|
|
13
|
-
}
|
|
14
9
|
/**
|
|
15
10
|
* Base class for feature adapters to extend. Defines some methods that
|
|
16
11
|
* subclasses must implement.
|
|
@@ -83,10 +78,7 @@ export class BaseFeatureDataAdapter extends BaseAdapter {
|
|
|
83
78
|
* features over a region, primarily used for quantitative tracks
|
|
84
79
|
*/
|
|
85
80
|
async getRegionQuantitativeStats(region, opts) {
|
|
86
|
-
const feats = this.getFeatures(region,
|
|
87
|
-
...opts,
|
|
88
|
-
statsEstimationMode: true,
|
|
89
|
-
});
|
|
81
|
+
const feats = this.getFeatures(region, opts);
|
|
90
82
|
return scoresToStats(region, feats);
|
|
91
83
|
}
|
|
92
84
|
/**
|
|
@@ -127,11 +119,11 @@ export class BaseFeatureDataAdapter extends BaseAdapter {
|
|
|
127
119
|
*/
|
|
128
120
|
async getFeatureDensity(regions, opts) {
|
|
129
121
|
const sidecar = this.getConf(['densityAdapter']);
|
|
130
|
-
const resolved =
|
|
122
|
+
const resolved = isSubAdapterConfig(sidecar) && this.getSubAdapter
|
|
131
123
|
? (await this.getSubAdapter(sidecar)).dataAdapter
|
|
132
124
|
: undefined;
|
|
133
125
|
if (resolved && !isFeatureAdapter(resolved)) {
|
|
134
|
-
throw new Error(`densityAdapter ${
|
|
126
|
+
throw new Error(`densityAdapter ${isSubAdapterConfig(sidecar) ? sidecar.type : ''} is not a feature adapter`);
|
|
135
127
|
}
|
|
136
128
|
return resolved
|
|
137
129
|
? Promise.all(regions.map(async (region) => {
|
|
@@ -27,3 +27,15 @@ export declare const densityAdapterConfigSchemaFields: {
|
|
|
27
27
|
readonly description: 'optional quantitative sub-adapter (e.g. a BigWigAdapter over a features-per-bin bigWig) drawn as a density band where the region is too large to fetch features; null disables it';
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Whether the `densityAdapter` slot holds something a sub-adapter can be built
|
|
32
|
+
* from. Beside the slot because both ends of the tier ask it and they have to
|
|
33
|
+
* agree: the display, deciding the band stands in, and `getFeatureDensity`,
|
|
34
|
+
* resolving the sidecar. They disagreed — the display took any object, the
|
|
35
|
+
* adapter wanted a type — so the shorthand every location slot accepts
|
|
36
|
+
* (`{ uri }`) turned the band on for a read that answered `undefined`, which
|
|
37
|
+
* commits nothing, and the phase then waited on bins no read would ever bring.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isSubAdapterConfig(value: unknown): value is Record<string, unknown> & {
|
|
40
|
+
type: string;
|
|
41
|
+
};
|
|
@@ -15,3 +15,18 @@ export const densityAdapterConfigSchemaFields = {
|
|
|
15
15
|
description: 'optional quantitative sub-adapter (e.g. a BigWigAdapter over a features-per-bin bigWig) drawn as a density band where the region is too large to fetch features; null disables it',
|
|
16
16
|
},
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Whether the `densityAdapter` slot holds something a sub-adapter can be built
|
|
20
|
+
* from. Beside the slot because both ends of the tier ask it and they have to
|
|
21
|
+
* agree: the display, deciding the band stands in, and `getFeatureDensity`,
|
|
22
|
+
* resolving the sidecar. They disagreed — the display took any object, the
|
|
23
|
+
* adapter wanted a type — so the shorthand every location slot accepts
|
|
24
|
+
* (`{ uri }`) turned the band on for a read that answered `undefined`, which
|
|
25
|
+
* commits nothing, and the phase then waited on bins no read would ever bring.
|
|
26
|
+
*/
|
|
27
|
+
export function isSubAdapterConfig(value) {
|
|
28
|
+
return (typeof value === 'object' &&
|
|
29
|
+
value !== null &&
|
|
30
|
+
'type' in value &&
|
|
31
|
+
typeof value.type === 'string');
|
|
32
|
+
}
|
|
@@ -3,11 +3,11 @@ import type { AnyConfigurationModel } from '../../configuration/index.ts';
|
|
|
3
3
|
import type { getSubAdapterType } from '../dataAdapterCache.ts';
|
|
4
4
|
import type { AnyDataAdapter } from './util.ts';
|
|
5
5
|
export { type AnyDataAdapter, isFeatureAdapter, isRefNameAliasAdapter, isRegionsAdapter, isSequenceAdapter, isTextSearchAdapter, } from './util.ts';
|
|
6
|
-
export type { BaseOptions,
|
|
6
|
+
export type { BaseOptions, BaseTextSearchArgs, LodTier, SearchType, } from './types.ts';
|
|
7
7
|
export { BaseAdapter } from './BaseAdapter.ts';
|
|
8
8
|
export { cachedSetup } from '../../util/cachedSetup.ts';
|
|
9
9
|
export { BaseFeatureDataAdapter } from './BaseFeatureDataAdapter.ts';
|
|
10
|
-
export { type FeatureDensity, densityAdapterConfigSchemaFields, } from './featureDensity.ts';
|
|
10
|
+
export { type FeatureDensity, densityAdapterConfigSchemaFields, isSubAdapterConfig, } from './featureDensity.ts';
|
|
11
11
|
export { BaseSequenceAdapter } from './BaseSequenceAdapter.ts';
|
|
12
12
|
export type { BaseTextSearchAdapter } from './BaseTextSearchAdapter.ts';
|
|
13
13
|
export type { Alias, BaseRefNameAliasAdapter, } from './BaseRefNameAliasAdapter.ts';
|
|
@@ -2,5 +2,5 @@ export { isFeatureAdapter, isRefNameAliasAdapter, isRegionsAdapter, isSequenceAd
|
|
|
2
2
|
export { BaseAdapter } from './BaseAdapter.js';
|
|
3
3
|
export { cachedSetup } from '../../util/cachedSetup.js';
|
|
4
4
|
export { BaseFeatureDataAdapter } from './BaseFeatureDataAdapter.js';
|
|
5
|
-
export { densityAdapterConfigSchemaFields, } from './featureDensity.js';
|
|
5
|
+
export { densityAdapterConfigSchemaFields, isSubAdapterConfig, } from './featureDensity.js';
|
|
6
6
|
export { BaseSequenceAdapter } from './BaseSequenceAdapter.js';
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
import type { StatusCallback } from '../../util/progress.ts';
|
|
2
2
|
import type { StopToken } from '../../util/stopToken.ts';
|
|
3
|
-
|
|
3
|
+
export type LodTier = 'fine' | 'coarse';
|
|
4
4
|
export interface BaseOptions {
|
|
5
5
|
stopToken?: StopToken;
|
|
6
6
|
bpPerPx?: number;
|
|
7
7
|
sessionId?: string;
|
|
8
|
-
trackInstanceId?: string;
|
|
9
8
|
signal?: AbortSignal;
|
|
10
9
|
statusCallback?: StatusCallback;
|
|
11
10
|
headers?: Record<string, string>;
|
|
12
|
-
statsEstimationMode?: boolean;
|
|
13
11
|
assemblyName?: string;
|
|
14
|
-
|
|
15
|
-
lodMode?: 'fine' | 'coarse';
|
|
12
|
+
lodMode?: LodTier;
|
|
16
13
|
topLevelOnly?: boolean;
|
|
17
14
|
}
|
|
18
|
-
export interface BaseOptionsWithRegions extends BaseOptions {
|
|
19
|
-
regions?: Region[];
|
|
20
|
-
}
|
|
21
15
|
export type SearchType = 'full' | 'prefix' | 'exact';
|
|
22
16
|
export interface BaseTextSearchArgs {
|
|
23
17
|
queryString: string;
|
|
@@ -42,7 +42,7 @@ export default class AdapterType extends PluggableElementBase {
|
|
|
42
42
|
* declaring the shorthand once gets both. It used to be a second, separate
|
|
43
43
|
* registration, and five in-tree adapters had only the schema half
|
|
44
44
|
* (`MafTabixAdapter`, `BgzipMafAdapter`, `BgzipTaffyAdapter`,
|
|
45
|
-
* `
|
|
45
|
+
* `MultiGenomePAFAdapter`, `MCScanBlocksAdapter`) — which reads as working,
|
|
46
46
|
* because loading such a config from a URL goes through the schema. Only
|
|
47
47
|
* `normalizeAdapterSnapshots` consults *this*, so what broke was `localFiles`
|
|
48
48
|
* in the embedded products: the shorthand stayed unexpanded, `uri` never
|
|
@@ -63,6 +63,7 @@ export default class AdapterType extends PluggableElementBase {
|
|
|
63
63
|
name: string;
|
|
64
64
|
configSchema: AnyConfigurationSchemaType;
|
|
65
65
|
displayName?: string;
|
|
66
|
+
aliases?: string[];
|
|
66
67
|
adapterCapabilities?: string[];
|
|
67
68
|
adapterMetadata?: AdapterMetadata;
|
|
68
69
|
normalizeSnapshot?: NormalizeSnapshot;
|
|
@@ -17,7 +17,7 @@ export default class AdapterType extends PluggableElementBase {
|
|
|
17
17
|
* declaring the shorthand once gets both. It used to be a second, separate
|
|
18
18
|
* registration, and five in-tree adapters had only the schema half
|
|
19
19
|
* (`MafTabixAdapter`, `BgzipMafAdapter`, `BgzipTaffyAdapter`,
|
|
20
|
-
* `
|
|
20
|
+
* `MultiGenomePAFAdapter`, `MCScanBlocksAdapter`) — which reads as working,
|
|
21
21
|
* because loading such a config from a URL goes through the schema. Only
|
|
22
22
|
* `normalizeAdapterSnapshots` consults *this*, so what broke was `localFiles`
|
|
23
23
|
* in the embedded products: the shorthand stayed unexpanded, `uri` never
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import LazyStateModelElement from './LazyStateModelElement.ts';
|
|
2
2
|
import type { AnyConfigurationSchemaType } from '../configuration/index.ts';
|
|
3
3
|
import type { AnyReactComponentType } from '../util/index.ts';
|
|
4
4
|
import type { IAnyModelType } from '@jbrowse/mobx-state-tree';
|
|
5
|
-
export default class DisplayType extends
|
|
6
|
-
|
|
7
|
-
get stateModel(): IAnyModelType;
|
|
8
|
-
stateModelLoader?: () => Promise<IAnyModelType>;
|
|
9
|
-
private stateModelPromise?;
|
|
10
|
-
private pendingStateModelExtensions;
|
|
5
|
+
export default class DisplayType extends LazyStateModelElement {
|
|
6
|
+
protected readonly group = "display";
|
|
11
7
|
configSchema: AnyConfigurationSchemaType;
|
|
12
8
|
ReactComponent: AnyReactComponentType;
|
|
13
9
|
/**
|
|
@@ -33,7 +29,4 @@ export default class DisplayType extends PluggableElementBase {
|
|
|
33
29
|
helpText?: string;
|
|
34
30
|
aliases?: string[];
|
|
35
31
|
});
|
|
36
|
-
get isStateModelLoaded(): boolean;
|
|
37
|
-
loadStateModel(): Promise<IAnyModelType>;
|
|
38
|
-
extendStateModel(extend: (stateModel: IAnyModelType) => IAnyModelType): void;
|
|
39
32
|
}
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
export default class DisplayType extends
|
|
3
|
-
|
|
4
|
-
// same contract as ViewType.stateModel
|
|
5
|
-
get stateModel() {
|
|
6
|
-
return this.loadedStateModel;
|
|
7
|
-
}
|
|
8
|
-
stateModelLoader;
|
|
9
|
-
stateModelPromise;
|
|
10
|
-
pendingStateModelExtensions = [];
|
|
1
|
+
import LazyStateModelElement from './LazyStateModelElement.js';
|
|
2
|
+
export default class DisplayType extends LazyStateModelElement {
|
|
3
|
+
group = 'display';
|
|
11
4
|
configSchema;
|
|
12
5
|
ReactComponent;
|
|
13
6
|
/**
|
|
@@ -24,45 +17,10 @@ export default class DisplayType extends PluggableElementBase {
|
|
|
24
17
|
helpText;
|
|
25
18
|
constructor(stuff) {
|
|
26
19
|
super(stuff);
|
|
27
|
-
if (typeof stuff.stateModel === 'function') {
|
|
28
|
-
this.stateModelLoader = stuff.stateModel;
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
this.loadedStateModel = stuff.stateModel;
|
|
32
|
-
}
|
|
33
20
|
this.configSchema = stuff.configSchema;
|
|
34
21
|
this.ReactComponent = stuff.ReactComponent;
|
|
35
22
|
this.trackType = stuff.trackType;
|
|
36
23
|
this.viewType = stuff.viewType;
|
|
37
24
|
this.helpText = stuff.helpText;
|
|
38
25
|
}
|
|
39
|
-
get isStateModelLoaded() {
|
|
40
|
-
return this.loadedStateModel !== undefined;
|
|
41
|
-
}
|
|
42
|
-
loadStateModel() {
|
|
43
|
-
if (this.loadedStateModel !== undefined) {
|
|
44
|
-
return Promise.resolve(this.loadedStateModel);
|
|
45
|
-
}
|
|
46
|
-
if (!this.stateModelLoader) {
|
|
47
|
-
throw new Error(`display type ${this.name} has neither a state model nor a loader`);
|
|
48
|
-
}
|
|
49
|
-
this.stateModelPromise ??= this.stateModelLoader().then(loaded => {
|
|
50
|
-
let stateModel = loaded;
|
|
51
|
-
for (const extend of this.pendingStateModelExtensions) {
|
|
52
|
-
stateModel = extend(stateModel);
|
|
53
|
-
}
|
|
54
|
-
this.pendingStateModelExtensions = [];
|
|
55
|
-
this.loadedStateModel = stateModel;
|
|
56
|
-
return stateModel;
|
|
57
|
-
});
|
|
58
|
-
return this.stateModelPromise;
|
|
59
|
-
}
|
|
60
|
-
extendStateModel(extend) {
|
|
61
|
-
if (this.loadedStateModel !== undefined) {
|
|
62
|
-
this.loadedStateModel = extend(this.loadedStateModel);
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
this.pendingStateModelExtensions.push(extend);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
26
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import PluggableElementBase from './PluggableElementBase.ts';
|
|
2
|
+
import type { IAnyModelType } from '@jbrowse/mobx-state-tree';
|
|
3
|
+
/**
|
|
4
|
+
* A pluggable element whose state model may arrive through a dynamic import.
|
|
5
|
+
* Code that can run before any instance exists — session preloading, pruning,
|
|
6
|
+
* union membership — checks `isStateModelLoaded` before reading `stateModel`.
|
|
7
|
+
*/
|
|
8
|
+
export default abstract class LazyStateModelElement extends PluggableElementBase {
|
|
9
|
+
protected abstract readonly group: 'view' | 'display';
|
|
10
|
+
private loadedStateModel?;
|
|
11
|
+
private stateModelPromise?;
|
|
12
|
+
private pendingStateModelExtensions;
|
|
13
|
+
stateModelLoader?: () => Promise<IAnyModelType>;
|
|
14
|
+
onStateModelLoaded?: () => void;
|
|
15
|
+
constructor(stuff: {
|
|
16
|
+
name: string;
|
|
17
|
+
displayName?: string;
|
|
18
|
+
aliases?: string[];
|
|
19
|
+
stateModel: IAnyModelType | (() => Promise<IAnyModelType>);
|
|
20
|
+
});
|
|
21
|
+
get stateModel(): IAnyModelType;
|
|
22
|
+
set stateModel(stateModel: IAnyModelType);
|
|
23
|
+
get isStateModelLoaded(): boolean;
|
|
24
|
+
assertStateModelLoaded(): void;
|
|
25
|
+
loadStateModel(): Promise<IAnyModelType>;
|
|
26
|
+
extendStateModel(extend: (stateModel: IAnyModelType) => IAnyModelType): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import PluggableElementBase from './PluggableElementBase.js';
|
|
2
|
+
/**
|
|
3
|
+
* A pluggable element whose state model may arrive through a dynamic import.
|
|
4
|
+
* Code that can run before any instance exists — session preloading, pruning,
|
|
5
|
+
* union membership — checks `isStateModelLoaded` before reading `stateModel`.
|
|
6
|
+
*/
|
|
7
|
+
export default class LazyStateModelElement extends PluggableElementBase {
|
|
8
|
+
loadedStateModel;
|
|
9
|
+
stateModelPromise;
|
|
10
|
+
pendingStateModelExtensions = [];
|
|
11
|
+
// named `stateModel` + `Loader` because pluggableMstType probes
|
|
12
|
+
// `${fieldName}Loader` generically
|
|
13
|
+
stateModelLoader;
|
|
14
|
+
// set by PluginManager.addElementType: runs Core-extendPluggableElement once
|
|
15
|
+
// the loader resolves, so a callback reading `stateModel` sees a model
|
|
16
|
+
onStateModelLoaded;
|
|
17
|
+
constructor(stuff) {
|
|
18
|
+
super(stuff);
|
|
19
|
+
if (typeof stuff.stateModel === 'function') {
|
|
20
|
+
this.stateModelLoader = stuff.stateModel;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
this.loadedStateModel = stuff.stateModel;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Throws before the loader resolves, so a plugin composing an unloaded
|
|
27
|
+
// model fails here rather than as an opaque MST error.
|
|
28
|
+
get stateModel() {
|
|
29
|
+
this.assertStateModelLoaded();
|
|
30
|
+
return this.loadedStateModel;
|
|
31
|
+
}
|
|
32
|
+
set stateModel(stateModel) {
|
|
33
|
+
this.loadedStateModel = stateModel;
|
|
34
|
+
}
|
|
35
|
+
get isStateModelLoaded() {
|
|
36
|
+
return this.loadedStateModel !== undefined;
|
|
37
|
+
}
|
|
38
|
+
assertStateModelLoaded() {
|
|
39
|
+
if (this.loadedStateModel === undefined) {
|
|
40
|
+
const getter = this.group === 'view' ? 'getViewType' : 'getDisplayType';
|
|
41
|
+
throw new Error(`state model for ${this.group} type ${this.name} is not loaded yet — await ${getter}('${this.name}').loadStateModel() first`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
loadStateModel() {
|
|
45
|
+
if (this.loadedStateModel !== undefined) {
|
|
46
|
+
return Promise.resolve(this.loadedStateModel);
|
|
47
|
+
}
|
|
48
|
+
if (!this.stateModelLoader) {
|
|
49
|
+
throw new Error(`${this.group} type ${this.name} has neither a state model nor a loader`);
|
|
50
|
+
}
|
|
51
|
+
this.stateModelPromise ??= this.stateModelLoader().then(loaded => {
|
|
52
|
+
let stateModel = loaded;
|
|
53
|
+
for (const extend of this.pendingStateModelExtensions) {
|
|
54
|
+
stateModel = extend(stateModel);
|
|
55
|
+
}
|
|
56
|
+
this.pendingStateModelExtensions = [];
|
|
57
|
+
this.loadedStateModel = stateModel;
|
|
58
|
+
this.onStateModelLoaded?.();
|
|
59
|
+
return this.stateModel;
|
|
60
|
+
});
|
|
61
|
+
return this.stateModelPromise;
|
|
62
|
+
}
|
|
63
|
+
extendStateModel(extend) {
|
|
64
|
+
if (this.loadedStateModel !== undefined) {
|
|
65
|
+
this.loadedStateModel = extend(this.loadedStateModel);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
this.pendingStateModelExtensions.push(extend);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import LazyStateModelElement from './LazyStateModelElement.ts';
|
|
2
2
|
import type { LaunchKeyRegistration } from '../util/withLaunchInput.ts';
|
|
3
3
|
import type DisplayType from './DisplayType.ts';
|
|
4
4
|
import type { IAnyModelType, IAnyStateTreeNode } from '@jbrowse/mobx-state-tree';
|
|
@@ -11,13 +11,9 @@ type ViewComponentType = React.LazyExoticComponent<BasicView> | BasicView;
|
|
|
11
11
|
interface ViewMetadata {
|
|
12
12
|
hiddenFromGUI?: boolean;
|
|
13
13
|
}
|
|
14
|
-
export default class ViewType extends
|
|
14
|
+
export default class ViewType extends LazyStateModelElement {
|
|
15
|
+
protected readonly group = "view";
|
|
15
16
|
ReactComponent: ViewComponentType;
|
|
16
|
-
private loadedStateModel?;
|
|
17
|
-
get stateModel(): IAnyModelType;
|
|
18
|
-
stateModelLoader?: () => Promise<IAnyModelType>;
|
|
19
|
-
private stateModelPromise?;
|
|
20
|
-
private pendingStateModelExtensions;
|
|
21
17
|
launchKeys?: LaunchKeyRegistration<unknown, string>;
|
|
22
18
|
displayTypes: DisplayType[];
|
|
23
19
|
viewMetadata: ViewMetadata;
|
|
@@ -45,9 +41,6 @@ export default class ViewType extends PluggableElementBase {
|
|
|
45
41
|
* a session spec launches straight through `LaunchView-<type>`.
|
|
46
42
|
*/
|
|
47
43
|
get acceptedKeys(): string[] | undefined;
|
|
48
|
-
get isStateModelLoaded(): boolean;
|
|
49
|
-
loadStateModel(): Promise<IAnyModelType>;
|
|
50
|
-
extendStateModel(extend: (stateModel: IAnyModelType) => IAnyModelType): void;
|
|
51
44
|
addDisplayType(display: DisplayType): void;
|
|
52
45
|
}
|
|
53
46
|
export {};
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
export default class ViewType extends
|
|
1
|
+
import LazyStateModelElement from './LazyStateModelElement.js';
|
|
2
|
+
export default class ViewType extends LazyStateModelElement {
|
|
3
|
+
group = 'view';
|
|
3
4
|
ReactComponent;
|
|
4
|
-
loadedStateModel;
|
|
5
|
-
// Non-optional because nearly every reader holds a view instance, which
|
|
6
|
-
// implies the model is loaded; code that can run before any instance exists
|
|
7
|
-
// (session preloading, pruning, union membership) must check
|
|
8
|
-
// isStateModelLoaded first.
|
|
9
|
-
get stateModel() {
|
|
10
|
-
return this.loadedStateModel;
|
|
11
|
-
}
|
|
12
|
-
// named `stateModel` + `Loader` because pluggableMstType and
|
|
13
|
-
// pruneUnbuildableNodes probe `${fieldName}Loader` generically
|
|
14
|
-
stateModelLoader;
|
|
15
|
-
stateModelPromise;
|
|
16
|
-
pendingStateModelExtensions = [];
|
|
17
5
|
// What `withLaunchInput` partitioned out of this view's snapshots, published
|
|
18
6
|
// beside the model so an out-of-tree plugin, the doc generator and the
|
|
19
7
|
// validator read one declaration rather than each keeping a list.
|
|
@@ -32,12 +20,6 @@ export default class ViewType extends PluggableElementBase {
|
|
|
32
20
|
super(stuff);
|
|
33
21
|
this.ReactComponent = stuff.ReactComponent;
|
|
34
22
|
this.viewMetadata = stuff.viewMetadata ?? {};
|
|
35
|
-
if (typeof stuff.stateModel === 'function') {
|
|
36
|
-
this.stateModelLoader = stuff.stateModel;
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
this.loadedStateModel = stuff.stateModel;
|
|
40
|
-
}
|
|
41
23
|
this.launchKeys = stuff.launchKeys;
|
|
42
24
|
this.extendedName = stuff.extendedName;
|
|
43
25
|
}
|
|
@@ -54,7 +36,9 @@ export default class ViewType extends PluggableElementBase {
|
|
|
54
36
|
* a session spec launches straight through `LaunchView-<type>`.
|
|
55
37
|
*/
|
|
56
38
|
get acceptedKeys() {
|
|
57
|
-
const properties = this.
|
|
39
|
+
const properties = this.isStateModelLoaded
|
|
40
|
+
? this.stateModel.properties
|
|
41
|
+
: undefined;
|
|
58
42
|
return this.launchKeys && properties
|
|
59
43
|
? [
|
|
60
44
|
...Object.keys(properties),
|
|
@@ -63,35 +47,6 @@ export default class ViewType extends PluggableElementBase {
|
|
|
63
47
|
]
|
|
64
48
|
: undefined;
|
|
65
49
|
}
|
|
66
|
-
get isStateModelLoaded() {
|
|
67
|
-
return this.loadedStateModel !== undefined;
|
|
68
|
-
}
|
|
69
|
-
loadStateModel() {
|
|
70
|
-
if (this.loadedStateModel !== undefined) {
|
|
71
|
-
return Promise.resolve(this.loadedStateModel);
|
|
72
|
-
}
|
|
73
|
-
if (!this.stateModelLoader) {
|
|
74
|
-
throw new Error(`view type ${this.name} has neither a state model nor a loader`);
|
|
75
|
-
}
|
|
76
|
-
this.stateModelPromise ??= this.stateModelLoader().then(loaded => {
|
|
77
|
-
let stateModel = loaded;
|
|
78
|
-
for (const extend of this.pendingStateModelExtensions) {
|
|
79
|
-
stateModel = extend(stateModel);
|
|
80
|
-
}
|
|
81
|
-
this.pendingStateModelExtensions = [];
|
|
82
|
-
this.loadedStateModel = stateModel;
|
|
83
|
-
return stateModel;
|
|
84
|
-
});
|
|
85
|
-
return this.stateModelPromise;
|
|
86
|
-
}
|
|
87
|
-
extendStateModel(extend) {
|
|
88
|
-
if (this.loadedStateModel !== undefined) {
|
|
89
|
-
this.loadedStateModel = extend(this.loadedStateModel);
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
this.pendingStateModelExtensions.push(extend);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
50
|
addDisplayType(display) {
|
|
96
51
|
this.displayTypes.push(display);
|
|
97
52
|
}
|
|
@@ -5,8 +5,7 @@ import type { IAnyModelType } from '@jbrowse/mobx-state-tree';
|
|
|
5
5
|
* Replace a view type's state model with an extended one, e.g. to add a menu
|
|
6
6
|
* item to `LinearGenomeView`. Pass an array to extend several at once, which is
|
|
7
7
|
* how a contribution reaches a family: the tree spells a display family as a
|
|
8
|
-
* shared mixin set rather than a chain, so there is no parent to name
|
|
9
|
-
* `reference/REJECTED_IDEAS.md`, "Give a pluggable element an `extendsType`".
|
|
8
|
+
* shared mixin set rather than a chain, so there is no parent to name, which is why an `extendsType` was declined.
|
|
10
9
|
*
|
|
11
10
|
* `Core-extendPluggableElement` fires for every pluggable element there is —
|
|
12
11
|
* adapters, widgets, RPC methods, all of them — so a callback written against
|
|
@@ -14,8 +14,7 @@ function namesOf(name) {
|
|
|
14
14
|
* Replace a view type's state model with an extended one, e.g. to add a menu
|
|
15
15
|
* item to `LinearGenomeView`. Pass an array to extend several at once, which is
|
|
16
16
|
* how a contribution reaches a family: the tree spells a display family as a
|
|
17
|
-
* shared mixin set rather than a chain, so there is no parent to name
|
|
18
|
-
* `reference/REJECTED_IDEAS.md`, "Give a pluggable element an `extendsType`".
|
|
17
|
+
* shared mixin set rather than a chain, so there is no parent to name, which is why an `extendsType` was declined.
|
|
19
18
|
*
|
|
20
19
|
* `Core-extendPluggableElement` fires for every pluggable element there is —
|
|
21
20
|
* adapters, widgets, RPC methods, all of them — so a callback written against
|