@genome-spy/core 0.76.0 → 0.78.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.
- package/LICENSE +21 -0
- package/dist/bundle/browser-KWU9rWZT.js +123 -0
- package/dist/bundle/esm-CT3ygiMq.js +1084 -0
- package/dist/bundle/{esm-D_euN86T.js → esm-DAnOffpD.js} +2 -2
- package/dist/bundle/{esm-BimDEpBb.js → esm-DNtC3H80.js} +2 -2
- package/dist/bundle/{esm-CngqBe45.js → esm-DVOHLB1e.js} +2 -2
- package/dist/bundle/esm-NIYEaYkc.js +1221 -0
- package/dist/bundle/index.es.js +3007 -2787
- package/dist/bundle/index.js +110 -99
- package/dist/schema.json +825 -112
- package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigWigSource.js +31 -11
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts +19 -3
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +34 -13
- package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
- package/dist/src/data/transforms/filterScoredLabels.js +3 -2
- package/dist/src/embedFactory.d.ts.map +1 -1
- package/dist/src/embedFactory.js +2 -0
- package/dist/src/genomeSpy/headlessBootstrap.d.ts.map +1 -1
- package/dist/src/genomeSpy/headlessBootstrap.js +2 -0
- package/dist/src/genomeSpy/interactionController.d.ts +4 -1
- package/dist/src/genomeSpy/interactionController.d.ts.map +1 -1
- package/dist/src/genomeSpy/interactionController.js +57 -13
- package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -1
- package/dist/src/genomeSpy/viewContextFactory.js +1 -0
- package/dist/src/genomeSpyBase.d.ts +6 -0
- package/dist/src/genomeSpyBase.d.ts.map +1 -1
- package/dist/src/genomeSpyBase.js +16 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/marks/__snapshots__/shaderSnapshot.test.js.snap +2 -2
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +0 -6
- package/dist/src/marks/rect.vertex.glsl.js +1 -1
- package/dist/src/minimal.d.ts +1 -0
- package/dist/src/minimal.d.ts.map +1 -1
- package/dist/src/minimal.js +1 -0
- package/dist/src/paramRuntime/embedParamApi.d.ts +26 -0
- package/dist/src/paramRuntime/embedParamApi.d.ts.map +1 -0
- package/dist/src/paramRuntime/embedParamApi.js +133 -0
- package/dist/src/scales/domainExpressions.d.ts +21 -0
- package/dist/src/scales/domainExpressions.d.ts.map +1 -0
- package/dist/src/scales/domainExpressions.js +43 -0
- package/dist/src/scales/domainPlanner.d.ts +12 -1
- package/dist/src/scales/domainPlanner.d.ts.map +1 -1
- package/dist/src/scales/domainPlanner.js +55 -36
- package/dist/src/scales/scaleInstanceManager.d.ts +1 -0
- package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
- package/dist/src/scales/scaleInstanceManager.js +5 -0
- package/dist/src/scales/scaleInteractionController.d.ts +8 -4
- package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
- package/dist/src/scales/scaleInteractionController.js +55 -7
- package/dist/src/scales/scalePropsResolver.d.ts +6 -1
- package/dist/src/scales/scalePropsResolver.d.ts.map +1 -1
- package/dist/src/scales/scalePropsResolver.js +35 -10
- package/dist/src/scales/scaleResolution.d.ts +19 -3
- package/dist/src/scales/scaleResolution.d.ts.map +1 -1
- package/dist/src/scales/scaleResolution.js +141 -20
- package/dist/src/scales/scaleRules.d.ts +10 -0
- package/dist/src/scales/scaleRules.d.ts.map +1 -1
- package/dist/src/scales/scaleRules.js +38 -1
- package/dist/src/scales/viewLevelScaleConfig.d.ts +45 -0
- package/dist/src/scales/viewLevelScaleConfig.d.ts.map +1 -0
- package/dist/src/scales/viewLevelScaleConfig.js +138 -0
- package/dist/src/selection/index.d.ts +8 -0
- package/dist/src/selection/index.d.ts.map +1 -0
- package/dist/src/selection/index.js +12 -0
- package/dist/src/spec/scale.d.ts +19 -6
- package/dist/src/spec/view.d.ts +11 -0
- package/dist/src/styles/genome-spy.css +12 -1
- package/dist/src/styles/genome-spy.css.d.ts +1 -1
- package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
- package/dist/src/styles/genome-spy.css.js +12 -1
- package/dist/src/types/embedApi.d.ts +54 -0
- package/dist/src/types/scaleResolutionApi.d.ts +28 -1
- package/dist/src/types/viewContext.d.ts +11 -0
- package/dist/src/utils/ui/tooltip.d.ts +4 -0
- package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
- package/dist/src/utils/ui/tooltip.js +57 -10
- package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
- package/dist/src/view/containerMutationHelper.js +11 -3
- package/package.json +3 -3
- package/dist/bundle/browser-BTgw5ieH.js +0 -126
- package/dist/bundle/esm-Bvlm1uVk.js +0 -1015
- package/dist/bundle/esm-C49STiCR.js +0 -1248
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("../spec/channel.js").ChannelWithScale} ChannelWithScale
|
|
3
|
+
* @typedef {import("../spec/scale.js").Scale} Scale
|
|
4
|
+
* @typedef {import("../view/view.js").default} View
|
|
5
|
+
* @typedef {import("./scaleResolution.js").default} ScaleResolution
|
|
6
|
+
*
|
|
7
|
+
* @typedef {object} ViewLevelScaleConfigMapping
|
|
8
|
+
* @prop {View} view
|
|
9
|
+
* @prop {ChannelWithScale} channel
|
|
10
|
+
* @prop {Scale} config
|
|
11
|
+
* @prop {ScaleResolution | undefined} resolution
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Maps view-level scale configs to the unique scale resolution visible from
|
|
16
|
+
* each configured subtree. Configs with no matching resolution stay pending.
|
|
17
|
+
*
|
|
18
|
+
* @param {View} root
|
|
19
|
+
* @returns {ViewLevelScaleConfigMapping[]}
|
|
20
|
+
*/
|
|
21
|
+
export function mapViewLevelScaleConfigs(root) {
|
|
22
|
+
/** @type {ViewLevelScaleConfigMapping[]} */
|
|
23
|
+
const mappings = [];
|
|
24
|
+
|
|
25
|
+
for (const view of root.getDescendants()) {
|
|
26
|
+
const scales = view.spec.scales;
|
|
27
|
+
if (!scales) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (const [channel, config] of Object.entries(scales)) {
|
|
32
|
+
mappings.push(
|
|
33
|
+
mapViewLevelScaleConfig(
|
|
34
|
+
view,
|
|
35
|
+
/** @type {ChannelWithScale} */ (channel),
|
|
36
|
+
config
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return mappings;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Maps view-level scale configs and attaches non-pending configs to their
|
|
47
|
+
* target resolutions.
|
|
48
|
+
*
|
|
49
|
+
* @param {View} root
|
|
50
|
+
* @returns {ViewLevelScaleConfigMapping[]}
|
|
51
|
+
*/
|
|
52
|
+
export function attachViewLevelScaleConfigs(root) {
|
|
53
|
+
clearViewLevelScaleConfigs(root);
|
|
54
|
+
const mappings = mapViewLevelScaleConfigs(root);
|
|
55
|
+
for (const mapping of mappings) {
|
|
56
|
+
if (mapping.resolution) {
|
|
57
|
+
mapping.resolution.attachViewLevelScaleConfig(
|
|
58
|
+
mapping.view,
|
|
59
|
+
mapping.config
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return mappings;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Clears view-level scale configs owned by views in the subtree.
|
|
68
|
+
*
|
|
69
|
+
* @param {View} root
|
|
70
|
+
*/
|
|
71
|
+
export function clearViewLevelScaleConfigs(root) {
|
|
72
|
+
const views = new Set(root.getDescendants());
|
|
73
|
+
const resolutions = collectAllScaleResolutions(root);
|
|
74
|
+
|
|
75
|
+
for (const resolution of resolutions) {
|
|
76
|
+
const config = resolution.getViewLevelScaleConfig();
|
|
77
|
+
if (config && views.has(config.view)) {
|
|
78
|
+
resolution.clearViewLevelScaleConfig(config.view);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {View} view
|
|
85
|
+
* @param {ChannelWithScale} channel
|
|
86
|
+
* @param {Scale} config
|
|
87
|
+
* @returns {ViewLevelScaleConfigMapping}
|
|
88
|
+
*/
|
|
89
|
+
function mapViewLevelScaleConfig(view, channel, config) {
|
|
90
|
+
const resolutions = collectVisibleScaleResolutions(view, channel);
|
|
91
|
+
|
|
92
|
+
if (resolutions.size > 1) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`View-level scales.${channel} maps to multiple scale resolutions. ` +
|
|
95
|
+
`Move scales.${channel} closer to the intended subtree or configure scale resolution explicitly.`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const resolution = resolutions.values().next().value;
|
|
100
|
+
return {
|
|
101
|
+
view,
|
|
102
|
+
channel,
|
|
103
|
+
config,
|
|
104
|
+
resolution,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {View} view
|
|
110
|
+
* @param {ChannelWithScale} channel
|
|
111
|
+
* @returns {Set<ScaleResolution>}
|
|
112
|
+
*/
|
|
113
|
+
function collectVisibleScaleResolutions(view, channel) {
|
|
114
|
+
/** @type {Set<ScaleResolution>} */
|
|
115
|
+
const resolutions = new Set();
|
|
116
|
+
for (const descendant of view.getDescendants()) {
|
|
117
|
+
const resolution = descendant.getScaleResolution(channel);
|
|
118
|
+
if (resolution) {
|
|
119
|
+
resolutions.add(resolution);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return resolutions;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @param {View} view
|
|
127
|
+
* @returns {Set<ScaleResolution>}
|
|
128
|
+
*/
|
|
129
|
+
function collectAllScaleResolutions(view) {
|
|
130
|
+
/** @type {Set<ScaleResolution>} */
|
|
131
|
+
const resolutions = new Set();
|
|
132
|
+
for (const descendant of view.getDescendants()) {
|
|
133
|
+
for (const resolution of Object.values(descendant.resolutions.scale)) {
|
|
134
|
+
resolutions.add(resolution);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return resolutions;
|
|
138
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a runtime interval selection value for use with parameter APIs.
|
|
3
|
+
*
|
|
4
|
+
* @param {Partial<Record<import("../spec/channel.js").PositionalChannel, [number, number] | null>>} intervals
|
|
5
|
+
* @returns {import("../types/selectionTypes.js").IntervalSelection}
|
|
6
|
+
*/
|
|
7
|
+
export function intervalSelection(intervals: Partial<Record<import("../spec/channel.js").PositionalChannel, [number, number] | null>>): import("../types/selectionTypes.js").IntervalSelection;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/selection/index.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,6CAHW,OAAO,CAAC,MAAM,CAAC,OAAO,oBAAoB,EAAE,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,GACtF,OAAO,4BAA4B,EAAE,iBAAiB,CAOlE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a runtime interval selection value for use with parameter APIs.
|
|
3
|
+
*
|
|
4
|
+
* @param {Partial<Record<import("../spec/channel.js").PositionalChannel, [number, number] | null>>} intervals
|
|
5
|
+
* @returns {import("../types/selectionTypes.js").IntervalSelection}
|
|
6
|
+
*/
|
|
7
|
+
export function intervalSelection(intervals) {
|
|
8
|
+
return {
|
|
9
|
+
type: "interval",
|
|
10
|
+
intervals: { ...intervals },
|
|
11
|
+
};
|
|
12
|
+
}
|
package/dist/src/spec/scale.d.ts
CHANGED
|
@@ -67,8 +67,17 @@ export interface Scale {
|
|
|
67
67
|
* For _temporal_ fields, `domain` can be a two-element array minimum and maximum values, in the form of either timestamps or the [DateTime definition objects](https://vega.github.io/vega-lite/docs/types.html#datetime).
|
|
68
68
|
*
|
|
69
69
|
* For _ordinal_ and _nominal_ fields, `domain` can be an array that lists valid input values.
|
|
70
|
+
|
|
71
|
+
* The domain can also be defined by an expression reference that evaluates to the domain array.
|
|
72
|
+
* Array elements may also be expression references.
|
|
73
|
+
*
|
|
70
74
|
*/
|
|
71
|
-
domain?:
|
|
75
|
+
domain?:
|
|
76
|
+
| ScalarDomain
|
|
77
|
+
| ComplexDomain
|
|
78
|
+
| SelectionDomainRef
|
|
79
|
+
| ExprRef
|
|
80
|
+
| DomainValueArray;
|
|
72
81
|
|
|
73
82
|
/**
|
|
74
83
|
* Inserts a single mid-point value into a two-element domain. The mid-point value must lie between the domain minimum and maximum values. This property can be useful for setting a midpoint for [diverging color scales](https://vega.github.io/vega-lite/docs/scale.html#piecewise). The domainMid property is only intended for use with scales supporting continuous, piecewise domains.
|
|
@@ -97,10 +106,10 @@ export interface Scale {
|
|
|
97
106
|
* transition.
|
|
98
107
|
*
|
|
99
108
|
* Set this to `false` to apply domain updates immediately. The default is
|
|
100
|
-
* `true`, except for domains
|
|
109
|
+
* `true`, except for domains that include `ExprRef`s, which default to
|
|
101
110
|
* `false` unless overridden.
|
|
102
111
|
*
|
|
103
|
-
* __Default value:__ `true`, except `false` for ExprRef
|
|
112
|
+
* __Default value:__ `true`, except `false` for `ExprRef`-driven domains.
|
|
104
113
|
*/
|
|
105
114
|
domainTransition?: boolean | Record<string, unknown>;
|
|
106
115
|
|
|
@@ -109,9 +118,9 @@ export interface Scale {
|
|
|
109
118
|
*
|
|
110
119
|
* - A string indicating a [pre-defined named scale range](https://vega.github.io/vega-lite/docs/scale.html#range-config) (e.g., example, `"symbol"`, or `"diverging"`).
|
|
111
120
|
*
|
|
112
|
-
* - For [continuous scales](https://vega.github.io/vega-lite/docs/scale.html#continuous), two-element array indicating
|
|
121
|
+
* - For [continuous scales](https://vega.github.io/vega-lite/docs/scale.html#continuous), two-element array indicating minimum and maximum values, or an array with more than two entries for specifying a [piecewise scale](https://vega.github.io/vega-lite/docs/scale.html#piecewise). Array elements may also be expression references.
|
|
113
122
|
*
|
|
114
|
-
* - For [discrete](https://vega.github.io/vega-lite/docs/scale.html#discrete) and [discretizing](https://vega.github.io/vega-lite/docs/scale.html#discretizing) scales, an array of desired output values.
|
|
123
|
+
* - For [discrete](https://vega.github.io/vega-lite/docs/scale.html#discrete) and [discretizing](https://vega.github.io/vega-lite/docs/scale.html#discretizing) scales, an array of desired output values. Array elements may also be expression references.
|
|
115
124
|
*
|
|
116
125
|
* __Notes:__
|
|
117
126
|
*
|
|
@@ -119,7 +128,7 @@ export interface Scale {
|
|
|
119
128
|
*
|
|
120
129
|
* 2) Any directly specified `range` for `x` and `y` channels will be ignored. Range can be customized via the view's corresponding [size](https://vega.github.io/vega-lite/docs/size.html) (`width` and `height`).
|
|
121
130
|
*/
|
|
122
|
-
range?: number
|
|
131
|
+
range?: (number | string | ExprRef)[] | string;
|
|
123
132
|
|
|
124
133
|
// ordinal
|
|
125
134
|
|
|
@@ -257,6 +266,10 @@ export interface Scale {
|
|
|
257
266
|
|
|
258
267
|
export type InlineLocusAssembly = GenomeDefinition;
|
|
259
268
|
|
|
269
|
+
export type DomainValue = number | string | boolean | ExprRef;
|
|
270
|
+
|
|
271
|
+
export type DomainValueArray = DomainValue[];
|
|
272
|
+
|
|
260
273
|
export interface SelectionDomainRef {
|
|
261
274
|
/**
|
|
262
275
|
* Name of an interval selection parameter that provides the domain.
|
package/dist/src/spec/view.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Data } from "./data.js";
|
|
|
2
2
|
import { TransformParams } from "./transform.js";
|
|
3
3
|
import {
|
|
4
4
|
Channel,
|
|
5
|
+
ChannelWithScale,
|
|
5
6
|
Encoding,
|
|
6
7
|
FacetFieldDef,
|
|
7
8
|
PrimaryPositionalChannel,
|
|
@@ -12,6 +13,7 @@ import { Title } from "./title.js";
|
|
|
12
13
|
import { Parameter } from "./parameter.js";
|
|
13
14
|
import { GenomeSpyConfig } from "./config.js";
|
|
14
15
|
import { ViewBackgroundProps, ZIndexProps } from "./decoration.js";
|
|
16
|
+
import { Scale } from "./scale.js";
|
|
15
17
|
|
|
16
18
|
export interface SizeDef {
|
|
17
19
|
/**
|
|
@@ -211,6 +213,15 @@ export interface ViewSpecBase extends ResolveSpec {
|
|
|
211
213
|
*/
|
|
212
214
|
config?: GenomeSpyConfig;
|
|
213
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Configures scale resolutions used by this view subtree.
|
|
218
|
+
*
|
|
219
|
+
* Use this when a composed view shares a scale across child views and the
|
|
220
|
+
* scale settings, such as the visible domain, belong to the composed view
|
|
221
|
+
* rather than an individual encoding.
|
|
222
|
+
*/
|
|
223
|
+
scales?: Partial<Record<ChannelWithScale, Scale>>;
|
|
224
|
+
|
|
214
225
|
/**
|
|
215
226
|
* Specifies a [data source](https://genomespy.app/docs/grammar/data/).
|
|
216
227
|
* If omitted, the data source is inherited from the parent view.
|
|
@@ -86,7 +86,10 @@
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
.tooltip {
|
|
89
|
-
position:
|
|
89
|
+
position: fixed;
|
|
90
|
+
inset: auto;
|
|
91
|
+
margin: 0;
|
|
92
|
+
border: 0;
|
|
90
93
|
|
|
91
94
|
max-width: 450px;
|
|
92
95
|
overflow: hidden;
|
|
@@ -177,6 +180,14 @@
|
|
|
177
180
|
}
|
|
178
181
|
}
|
|
179
182
|
|
|
183
|
+
.autoscroll-container {
|
|
184
|
+
max-height: min(40em, 50vh);
|
|
185
|
+
overflow-x: hidden;
|
|
186
|
+
overflow-y: auto;
|
|
187
|
+
padding-right: var(--genome-spy-basic-spacing);
|
|
188
|
+
margin-right: calc(-1 * var(--genome-spy-basic-spacing));
|
|
189
|
+
}
|
|
190
|
+
|
|
180
191
|
.na {
|
|
181
192
|
color: #aaa;
|
|
182
193
|
font-style: italic;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export default css;
|
|
2
|
-
declare const css: "\n@scope {\n:scope {\n--genome-spy-basic-spacing: 10px;\n--genome-spy-font-family:\nsystem-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif,\n\"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n\nfont-family: var(--genome-spy-font-family);\n\nposition: relative;\n\ndisplay: flex;\nflex-direction: column;\n}\n\n.canvas-wrapper {\nposition: relative;\nflex-grow: 1;\noverflow: hidden;\n}\n\ncanvas {\ndisplay: block;\ntouch-action: none;\ntransform: scale(1, 1);\nopacity: 1;\ntransition:\ntransform 0.6s,\nopacity 0.6s;\n\n&:focus,\n&:focus-visible {\noutline: none;\n}\n}\n\n.loading {\n> canvas {\ntransform: scale(0.95, 0.95);\nopacity: 0;\n}\n}\n\n.loading-indicators {\nposition: absolute;\ninset: 0;\n\nuser-select: none;\npointer-events: none;\n\ndiv {\nposition: absolute;\ndisplay: flex;\nalign-items: center;\njustify-content: center;\n\n> div {\nfont-size: 11px;\ntransition: opacity 0.2s;\nbackground: white;\npadding: 2px 5px;\ndisplay: flex;\nborder-radius: 3px;\ngap: 0.5em;\nopacity: 0;\n\n&.loading {\nopacity: 0.5;\n}\n\n&.error {\nopacity: 0.8;\ncolor: firebrick;\n}\n\n> * {\ndisplay: block;\n}\n\nimg {\nwidth: 1.5em;\nheight: 1.5em;\n}\n}\n}\n}\n\n.tooltip {\nposition:
|
|
2
|
+
declare const css: "\n@scope {\n:scope {\n--genome-spy-basic-spacing: 10px;\n--genome-spy-font-family:\nsystem-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif,\n\"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n\nfont-family: var(--genome-spy-font-family);\n\nposition: relative;\n\ndisplay: flex;\nflex-direction: column;\n}\n\n.canvas-wrapper {\nposition: relative;\nflex-grow: 1;\noverflow: hidden;\n}\n\ncanvas {\ndisplay: block;\ntouch-action: none;\ntransform: scale(1, 1);\nopacity: 1;\ntransition:\ntransform 0.6s,\nopacity 0.6s;\n\n&:focus,\n&:focus-visible {\noutline: none;\n}\n}\n\n.loading {\n> canvas {\ntransform: scale(0.95, 0.95);\nopacity: 0;\n}\n}\n\n.loading-indicators {\nposition: absolute;\ninset: 0;\n\nuser-select: none;\npointer-events: none;\n\ndiv {\nposition: absolute;\ndisplay: flex;\nalign-items: center;\njustify-content: center;\n\n> div {\nfont-size: 11px;\ntransition: opacity 0.2s;\nbackground: white;\npadding: 2px 5px;\ndisplay: flex;\nborder-radius: 3px;\ngap: 0.5em;\nopacity: 0;\n\n&.loading {\nopacity: 0.5;\n}\n\n&.error {\nopacity: 0.8;\ncolor: firebrick;\n}\n\n> * {\ndisplay: block;\n}\n\nimg {\nwidth: 1.5em;\nheight: 1.5em;\n}\n}\n}\n}\n\n.tooltip {\nposition: fixed;\ninset: auto;\nmargin: 0;\nborder: 0;\n\nmax-width: 450px;\noverflow: hidden;\n\n--background-color: #f6f6f6;\nbackground: var(--background-color);\npadding: var(--genome-spy-basic-spacing);\n\n--font-size: 12px;\nfont-size: var(--font-size);\n\nbox-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);\n\n&:not(.sticky) {\npointer-events: none;\n}\n\ntransition:\noutline-color 0.3s ease-in-out,\nbox-shadow 0.3s ease-in-out;\n\noutline: 0px solid transparent;\n&.sticky {\noutline: 2px solid black;\nbox-shadow: 0px 3px 18px 0px rgba(0, 0, 0, 0.3);\n}\n\nz-index: 100;\n\n> :last-child {\nmargin-bottom: 0;\n}\n\n> .title {\npadding-bottom: calc(var(--genome-spy-basic-spacing) / 2);\nmargin-bottom: calc(var(--genome-spy-basic-spacing) / 2);\nborder-bottom: 1px dashed var(--background-color);\nborder-bottom: 1px dashed\ncolor-mix(in srgb, black 25%, var(--background-color));\n}\n\n.summary {\nfont-size: 12px;\n}\n\ntable {\n&:first-child {\nmargin-top: 0;\n}\n\nborder-collapse: collapse;\n\nth,\ntd {\npadding: 2px 0.4em;\nvertical-align: top;\nfont-size: var(--font-size);\n\n&:first-child {\npadding-left: 0;\n}\n}\n\nth {\ntext-align: left;\nfont-weight: bold;\n}\n}\n\n.color-legend {\ndisplay: inline-block;\nwidth: 0.8em;\nheight: 0.8em;\nmargin-left: 0.4em;\nbox-shadow: 0px 0px 3px 1px white;\n}\n\n.color-legend-unmapped {\nbackground-color: transparent;\nborder: 1px solid black;\nbox-sizing: border-box;\nbox-shadow: none;\n}\n\n.attributes {\n.hovered {\nbackground-color: #e0e0e0;\n}\n}\n\n.autoscroll-container {\nmax-height: min(40em, 50vh);\noverflow-x: hidden;\noverflow-y: auto;\npadding-right: var(--genome-spy-basic-spacing);\nmargin-right: calc(-1 * var(--genome-spy-basic-spacing));\n}\n\n.na {\ncolor: #aaa;\nfont-style: italic;\nfont-size: 80%;\n}\n}\n\n.gene-track-tooltip {\n.summary {\nfont-size: 90%;\n}\n}\n\n.gs-input-binding {\ndisplay: grid;\ngrid-template-columns: max-content max-content;\ncolumn-gap: 1em;\nrow-gap: 0.3em;\njustify-items: start;\n\n> select,\n> input:not([type=\"checkbox\"]) {\nwidth: 100%;\n}\n\ninput[type=\"range\"] + span {\ndisplay: inline-block;\nmargin-left: 0.3em;\nmin-width: 2.2em;\nfont-variant-numeric: tabular-nums;\n}\n\ninput[type=\"range\"],\ninput[type=\"radio\"] {\nvertical-align: text-bottom;\n}\n\n.radio-group {\ndisplay: flex;\nalign-items: center;\n}\n\n.description {\nmax-width: 26em;\ngrid-column: 1 / -1;\ncolor: #777;\nfont-size: 90%;\nmargin-top: -0.5em;\n}\n}\n\n.gs-input-bindings {\nflex-basis: content;\nfont-size: 14px;\npadding: var(--genome-spy-basic-spacing);\n}\n\n.message-box {\ndisplay: flex;\nalign-items: center;\njustify-content: center;\nposition: absolute;\ntop: 0;\nheight: 100%;\nwidth: 100%;\n\n> div {\nborder: 1px solid red;\npadding: 10px;\nbackground: #fff0f0;\n}\n}\n}\n";
|
|
3
3
|
//# sourceMappingURL=genome-spy.css.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genome-spy.css.d.ts","sourceRoot":"","sources":["../../../src/styles/genome-spy.css.js"],"names":[],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"genome-spy.css.d.ts","sourceRoot":"","sources":["../../../src/styles/genome-spy.css.js"],"names":[],"mappings":";AAAA,o7HAwQE"}
|
|
@@ -87,7 +87,10 @@ height: 1.5em;
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
.tooltip {
|
|
90
|
-
position:
|
|
90
|
+
position: fixed;
|
|
91
|
+
inset: auto;
|
|
92
|
+
margin: 0;
|
|
93
|
+
border: 0;
|
|
91
94
|
|
|
92
95
|
max-width: 450px;
|
|
93
96
|
overflow: hidden;
|
|
@@ -178,6 +181,14 @@ background-color: #e0e0e0;
|
|
|
178
181
|
}
|
|
179
182
|
}
|
|
180
183
|
|
|
184
|
+
.autoscroll-container {
|
|
185
|
+
max-height: min(40em, 50vh);
|
|
186
|
+
overflow-x: hidden;
|
|
187
|
+
overflow-y: auto;
|
|
188
|
+
padding-right: var(--genome-spy-basic-spacing);
|
|
189
|
+
margin-right: calc(-1 * var(--genome-spy-basic-spacing));
|
|
190
|
+
}
|
|
191
|
+
|
|
181
192
|
.na {
|
|
182
193
|
color: #aaa;
|
|
183
194
|
font-style: italic;
|
|
@@ -2,6 +2,8 @@ import { ScaleResolutionApi } from "./scaleResolutionApi.js";
|
|
|
2
2
|
import { TooltipHandler } from "../tooltip/tooltipHandler.js";
|
|
3
3
|
import { RootSpec } from "../spec/root.js";
|
|
4
4
|
import { GenomeSpyConfig } from "../spec/config.js";
|
|
5
|
+
import { Scalar } from "../spec/channel.js";
|
|
6
|
+
import { IntervalSelection } from "./selectionTypes.js";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Embeds GenomeSpy into the DOM
|
|
@@ -54,6 +56,47 @@ export interface EmbedOptions {
|
|
|
54
56
|
onError?: (error: unknown, container: HTMLElement) => boolean | void;
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Runtime value type covered by the default embed parameter API.
|
|
61
|
+
*
|
|
62
|
+
* The default type covers scalar variable parameters and interval selections.
|
|
63
|
+
* Object and array variable parameters are supported at runtime, but callers
|
|
64
|
+
* should provide their own generic type when accessing them:
|
|
65
|
+
*
|
|
66
|
+
* `const param = api.getParam<MyValue>("myParam")`
|
|
67
|
+
*
|
|
68
|
+
* Current limitations:
|
|
69
|
+
*
|
|
70
|
+
* - Parameters are addressed by name only. Independent same-name parameters
|
|
71
|
+
* throw an ambiguity error.
|
|
72
|
+
* - Computed `expr` parameters are readable but cannot be written.
|
|
73
|
+
* - Point selections are readable as runtime values but are not supported for
|
|
74
|
+
* writes through the initial API because valid values require
|
|
75
|
+
* GenomeSpy-generated datum ids.
|
|
76
|
+
* - Projected selections are not supported.
|
|
77
|
+
*/
|
|
78
|
+
export type ParamValue = Scalar | null | undefined | IntervalSelection;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A handle for reading, writing, and subscribing to an explicit parameter.
|
|
82
|
+
*/
|
|
83
|
+
export interface ParamApi<T = ParamValue> {
|
|
84
|
+
/**
|
|
85
|
+
* Returns the current parameter value.
|
|
86
|
+
*/
|
|
87
|
+
getValue: () => T;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Sets the parameter value. Computed `expr` parameters throw when set.
|
|
91
|
+
*/
|
|
92
|
+
setValue: (value: T) => void;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Subscribes to parameter changes. Returns an unsubscribe function.
|
|
96
|
+
*/
|
|
97
|
+
subscribe: (listener: (value: T) => void) => () => void;
|
|
98
|
+
}
|
|
99
|
+
|
|
57
100
|
/**
|
|
58
101
|
* An API for controlling the embedded GenomeSpy instance.
|
|
59
102
|
*/
|
|
@@ -82,6 +125,17 @@ export interface EmbedResult {
|
|
|
82
125
|
*/
|
|
83
126
|
getScaleResolutionByName: (name: string) => ScaleResolutionApi;
|
|
84
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Returns a handle for reading, writing, and subscribing to a named
|
|
130
|
+
* parameter.
|
|
131
|
+
*
|
|
132
|
+
* Parameters are addressed by name only. If the name resolves to multiple
|
|
133
|
+
* independent parameters, this method throws an ambiguity error. Parameters
|
|
134
|
+
* declared with `push: "outer"` are treated as aliases of the outer
|
|
135
|
+
* parameter they write to.
|
|
136
|
+
*/
|
|
137
|
+
getParam: <T = ParamValue>(name: string) => ParamApi<T>;
|
|
138
|
+
|
|
85
139
|
/**
|
|
86
140
|
* Waits until lazy data sources have loaded data for the current visible
|
|
87
141
|
* positional domain.
|
|
@@ -10,6 +10,25 @@ export interface ScaleResolutionEvent {
|
|
|
10
10
|
|
|
11
11
|
export type ScaleResolutionListener = (event: ScaleResolutionEvent) => void;
|
|
12
12
|
|
|
13
|
+
export interface ZoomToOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Approximate transition duration. Zero or omitted zooms immediately.
|
|
16
|
+
* Boolean `true` indicates a default duration.
|
|
17
|
+
*/
|
|
18
|
+
duration?: boolean | number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Render immediately without scheduling an animation frame.
|
|
22
|
+
*
|
|
23
|
+
* This is intended for synchronizing multiple GenomeSpy instances, where
|
|
24
|
+
* the target view should be redrawn during the same animation frame as the
|
|
25
|
+
* source view. Use it only for zero-duration zooms. It is not supported for
|
|
26
|
+
* animated transitions and may do redundant work if several domains are
|
|
27
|
+
* applied before the browser has a chance to paint.
|
|
28
|
+
*/
|
|
29
|
+
renderImmediately?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
13
32
|
/**
|
|
14
33
|
* A public API for ScaleResolution
|
|
15
34
|
*/
|
|
@@ -59,6 +78,14 @@ export interface ScaleResolutionApi {
|
|
|
59
78
|
|
|
60
79
|
zoomTo(
|
|
61
80
|
domain: number[] | ComplexDomain,
|
|
62
|
-
|
|
81
|
+
options?: ZoomToOptions
|
|
82
|
+
): Promise<void>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @deprecated Use the options object form: `zoomTo(domain, { duration })`.
|
|
86
|
+
*/
|
|
87
|
+
zoomTo(
|
|
88
|
+
domain: number[] | ComplexDomain,
|
|
89
|
+
duration: boolean | number
|
|
63
90
|
): Promise<void>;
|
|
64
91
|
}
|
|
@@ -34,6 +34,17 @@ export default interface ViewContext {
|
|
|
34
34
|
|
|
35
35
|
requestLayoutReflow: () => void;
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Renders the current scene immediately without scheduling an animation frame.
|
|
39
|
+
*
|
|
40
|
+
* This is intended for synchronization paths where another GenomeSpy
|
|
41
|
+
* instance is already rendering the current animation frame and this view
|
|
42
|
+
* must repaint after a synchronous state update, such as linked scale
|
|
43
|
+
* domains. Callers should use the animator for ordinary rendering. Calling
|
|
44
|
+
* this repeatedly before the browser paints may do redundant work.
|
|
45
|
+
*/
|
|
46
|
+
renderImmediately: () => void;
|
|
47
|
+
|
|
37
48
|
updateTooltip: <T>(
|
|
38
49
|
datum: T,
|
|
39
50
|
converter?: (datum: T) => Promise<TemplateResult>
|
|
@@ -16,6 +16,10 @@ export default class Tooltip {
|
|
|
16
16
|
set visible(visible: boolean);
|
|
17
17
|
get visible(): boolean;
|
|
18
18
|
get enabled(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* @param {Event} event
|
|
21
|
+
*/
|
|
22
|
+
containsEvent(event: Event): boolean;
|
|
19
23
|
/**
|
|
20
24
|
* @param {boolean} enabled True if tooltip is enabled (allowed to be shown)
|
|
21
25
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../../src/utils/ui/tooltip.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../../src/utils/ui/tooltip.js"],"names":[],"mappings":"AAGA,0CAA2C,qBAAqB,CAAC;AACjE,4CAA6C,uBAAuB,CAAC;AAErE;IAqBI;;OAEG;IACH,uBAFW,WAAW,EASrB;IAED;;OAEG;IACH,mBAFW,OAAO,EAQjB;IAED,cAVW,OAAO,CAYjB;IAED;;OAEG;IACH,qBAFW,OAAO,EAQjB;IAED,eAVW,OAAO,CAYjB;IAED,uBAEC;IAED;;OAEG;IACH,qBAFW,KAAK,WAIf;IAED;;OAEG;IACH,0BAFW,OAAO,QAOjB;IAED,wBAEC;IAED;;OAEG;IACH,4BAFW,UAAU,QAyCpB;IAlCG,8BAGE;IAiCN,wBAiBC;IAED;;OAEG;IACH,oBAFW,MAAM,GAAG,OAAO,KAAK,EAAE,cAAc,GAAG,WAAW,QAwB7D;IAED,cAGC;IAED;;;;;;;OAOG;IACH,gBAFa,CAAC,SAFH,CAAC,cACD,CAAS,IAAC,EAAD,CAAC,KAAE,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAyBlF;IAED,sBAEC;;CAkBJ"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import clientPoint from "../point.js";
|
|
2
1
|
import { html, render } from "lit";
|
|
3
2
|
import { peek } from "../arrayUtils.js";
|
|
4
3
|
|
|
@@ -22,8 +21,7 @@ export default class Tooltip {
|
|
|
22
21
|
/** @type {HTMLDivElement} */
|
|
23
22
|
#element;
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
#container;
|
|
24
|
+
#popoverOpen = false;
|
|
27
25
|
|
|
28
26
|
#enabledStack = [true];
|
|
29
27
|
|
|
@@ -31,11 +29,10 @@ export default class Tooltip {
|
|
|
31
29
|
* @param {HTMLElement} container
|
|
32
30
|
*/
|
|
33
31
|
constructor(container) {
|
|
34
|
-
this.#container = container;
|
|
35
|
-
|
|
36
32
|
this.#element = document.createElement("div");
|
|
37
33
|
this.#element.className = "tooltip";
|
|
38
|
-
this.#
|
|
34
|
+
this.#element.setAttribute("popover", "manual");
|
|
35
|
+
container.appendChild(this.#element);
|
|
39
36
|
|
|
40
37
|
this.clear();
|
|
41
38
|
}
|
|
@@ -61,6 +58,7 @@ export default class Tooltip {
|
|
|
61
58
|
set visible(visible) {
|
|
62
59
|
if (visible != this.#visible) {
|
|
63
60
|
this.#element.style.display = visible ? null : "none";
|
|
61
|
+
this.#setPopoverOpen(visible);
|
|
64
62
|
this.#visible = visible;
|
|
65
63
|
}
|
|
66
64
|
}
|
|
@@ -73,6 +71,13 @@ export default class Tooltip {
|
|
|
73
71
|
return peek(this.#enabledStack) ?? true;
|
|
74
72
|
}
|
|
75
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @param {Event} event
|
|
76
|
+
*/
|
|
77
|
+
containsEvent(event) {
|
|
78
|
+
return event.composedPath().includes(this.#element);
|
|
79
|
+
}
|
|
80
|
+
|
|
76
81
|
/**
|
|
77
82
|
* @param {boolean} enabled True if tooltip is enabled (allowed to be shown)
|
|
78
83
|
*/
|
|
@@ -95,7 +100,10 @@ export default class Tooltip {
|
|
|
95
100
|
return;
|
|
96
101
|
}
|
|
97
102
|
|
|
98
|
-
this.mouseCoords =
|
|
103
|
+
this.mouseCoords = /** @type {[number, number]} */ ([
|
|
104
|
+
mouseEvent.clientX,
|
|
105
|
+
mouseEvent.clientY,
|
|
106
|
+
]);
|
|
99
107
|
|
|
100
108
|
const now = performance.now();
|
|
101
109
|
|
|
@@ -130,12 +138,12 @@ export default class Tooltip {
|
|
|
130
138
|
|
|
131
139
|
updatePlacement() {
|
|
132
140
|
/** Space between pointer and tooltip box */
|
|
133
|
-
const spacing =
|
|
141
|
+
const spacing = 10;
|
|
134
142
|
|
|
135
143
|
const [mouseX, mouseY] = this.mouseCoords;
|
|
136
144
|
|
|
137
145
|
let x = mouseX + spacing;
|
|
138
|
-
if (x >
|
|
146
|
+
if (x > window.innerWidth - spacing - this.#element.offsetWidth) {
|
|
139
147
|
x = mouseX - spacing - this.#element.offsetWidth;
|
|
140
148
|
}
|
|
141
149
|
this.#element.style.left = x + "px";
|
|
@@ -143,7 +151,7 @@ export default class Tooltip {
|
|
|
143
151
|
this.#element.style.top =
|
|
144
152
|
Math.min(
|
|
145
153
|
mouseY + spacing,
|
|
146
|
-
|
|
154
|
+
window.innerHeight - spacing - this.#element.offsetHeight
|
|
147
155
|
) + "px";
|
|
148
156
|
}
|
|
149
157
|
|
|
@@ -165,6 +173,9 @@ export default class Tooltip {
|
|
|
165
173
|
}
|
|
166
174
|
|
|
167
175
|
render(content, this.#element);
|
|
176
|
+
this.#element
|
|
177
|
+
.querySelectorAll(".autoscroll-container")
|
|
178
|
+
.forEach(scrollHoveredTooltipRow);
|
|
168
179
|
|
|
169
180
|
this.visible = true;
|
|
170
181
|
|
|
@@ -211,6 +222,42 @@ export default class Tooltip {
|
|
|
211
222
|
_isPenalty() {
|
|
212
223
|
return this.#penaltyUntil && this.#penaltyUntil > performance.now();
|
|
213
224
|
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @param {boolean} open
|
|
228
|
+
*/
|
|
229
|
+
#setPopoverOpen(open) {
|
|
230
|
+
if (open == this.#popoverOpen) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (open && this.#element.showPopover) {
|
|
235
|
+
this.#element.showPopover();
|
|
236
|
+
} else if (!open && this.#element.hidePopover) {
|
|
237
|
+
this.#element.hidePopover();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.#popoverOpen = open;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Scrolls the highlighted tooltip row into view after Lit has committed the
|
|
246
|
+
* current render.
|
|
247
|
+
*
|
|
248
|
+
* @param {Element | undefined} element
|
|
249
|
+
*/
|
|
250
|
+
function scrollHoveredTooltipRow(element) {
|
|
251
|
+
if (!element) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
queueMicrotask(() => {
|
|
256
|
+
element.querySelector("tr.hovered")?.scrollIntoView({
|
|
257
|
+
block: "nearest",
|
|
258
|
+
inline: "nearest",
|
|
259
|
+
});
|
|
260
|
+
});
|
|
214
261
|
}
|
|
215
262
|
|
|
216
263
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containerMutationHelper.d.ts","sourceRoot":"","sources":["../../../src/view/containerMutationHelper.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"containerMutationHelper.d.ts","sourceRoot":"","sources":["../../../src/view/containerMutationHelper.js"],"names":[],"mappings":"AAYA;;;GAGG;AACH;IACI;;;;;;;;;;OAUG;IAEH;;;;;;;;;;;OAWG;IAEH;;;OAGG;IACH,uBAHW,OAAO,oBAAoB,EAAE,OAAO;uBAZ3B;mBARR,CAAC,yEAAqB,CAAC,EAAE;sBACtB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,yEAAqB,KAAK,IAAI;sBACpD,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;SAMF;oBACnB,CAAC,IAAI,iEAAM,EAAE,KAAK,EAAE,MAAM,KAAK,GAAG;oBAClC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;sBACrB,CAAC,IAAI,iEAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC;sBAClE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;sBAChC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,yEAAqB,KAAK,MAAM;4BAChD,OAAO,yBAAyB,EAAE,iBAAiB;wBACvD,OAAO;OAW3B;IAFG,yFAA0B;IAC1B;uBAjBgB;mBARR,CAAC,yEAAqB,CAAC,EAAE;sBACtB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,yEAAqB,KAAK,IAAI;sBACpD,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;SAMF;oBACnB,CAAC,IAAI,iEAAM,EAAE,KAAK,EAAE,MAAM,KAAK,GAAG;oBAClC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;sBACrB,CAAC,IAAI,iEAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC;sBAClE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;sBAChC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,yEAAqB,KAAK,MAAM;4BAChD,OAAO,yBAAyB,EAAE,iBAAiB;wBACvD,OAAO;MAUF;IAG1B;;;;;;OAMG;IACH,wBAJW,OAAO,iBAAiB,EAAE,QAAQ,GAAG,OAAO,iBAAiB,EAAE,UAAU,UACzE,MAAM,GACJ,OAAO,iEAAM,CAyDzB;IAED;;;;OAIG;IACH,qBAFW,MAAM,iBAiBhB;CACJ"}
|