@genome-spy/core 0.44.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/bundle/index.es.js +6123 -5482
  2. package/dist/bundle/index.js +211 -148
  3. package/dist/schema.json +329 -79
  4. package/dist/src/data/collector.d.ts.map +1 -1
  5. package/dist/src/data/collector.js +4 -2
  6. package/dist/src/data/flowOptimizer.test.js +12 -3
  7. package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
  8. package/dist/src/data/sources/dataUtils.js +3 -1
  9. package/dist/src/data/sources/lazy/bigBedSource.d.ts +1 -1
  10. package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
  11. package/dist/src/data/sources/lazy/bigBedSource.js +52 -20
  12. package/dist/src/data/sources/lazy/bigWigSource.d.ts +0 -1
  13. package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
  14. package/dist/src/data/sources/lazy/bigWigSource.js +30 -4
  15. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
  16. package/dist/src/data/sources/lazy/singleAxisLazySource.js +0 -2
  17. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts +6 -2
  18. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  19. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +38 -20
  20. package/dist/src/data/sources/sequenceSource.d.ts.map +1 -1
  21. package/dist/src/data/sources/sequenceSource.js +14 -5
  22. package/dist/src/data/sources/sequenceSource.test.js +23 -5
  23. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  24. package/dist/src/data/sources/urlSource.js +15 -2
  25. package/dist/src/data/transforms/aggregate.d.ts.map +1 -1
  26. package/dist/src/data/transforms/aggregate.js +5 -2
  27. package/dist/src/encoder/encoder.d.ts +2 -4
  28. package/dist/src/encoder/encoder.d.ts.map +1 -1
  29. package/dist/src/encoder/encoder.js +8 -8
  30. package/dist/src/encoder/encoder.test.js +3 -0
  31. package/dist/src/genomeSpy.d.ts +7 -5
  32. package/dist/src/genomeSpy.d.ts.map +1 -1
  33. package/dist/src/genomeSpy.js +109 -132
  34. package/dist/src/gl/glslScaleGenerator.js +1 -1
  35. package/dist/src/index.d.ts +1 -1
  36. package/dist/src/index.d.ts.map +1 -1
  37. package/dist/src/index.js +1 -1
  38. package/dist/src/marks/mark.d.ts +8 -5
  39. package/dist/src/marks/mark.d.ts.map +1 -1
  40. package/dist/src/marks/mark.js +56 -12
  41. package/dist/src/marks/point.common.glsl.js +1 -1
  42. package/dist/src/marks/point.d.ts +1 -4
  43. package/dist/src/marks/point.d.ts.map +1 -1
  44. package/dist/src/marks/point.js +31 -23
  45. package/dist/src/marks/point.vertex.glsl.js +1 -1
  46. package/dist/src/marks/text.d.ts.map +1 -1
  47. package/dist/src/marks/text.js +15 -7
  48. package/dist/src/spec/data.d.ts +11 -10
  49. package/dist/src/spec/mark.d.ts +11 -21
  50. package/dist/src/spec/parameter.d.ts +11 -7
  51. package/dist/src/spec/root.d.ts +0 -8
  52. package/dist/src/spec/title.d.ts +5 -4
  53. package/dist/src/spec/view.d.ts +19 -4
  54. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  55. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  56. package/dist/src/styles/genome-spy.css.js +52 -5
  57. package/dist/src/styles/genome-spy.scss +63 -10
  58. package/dist/src/styles/update.sh +6 -0
  59. package/dist/src/tooltip/dataTooltipHandler.js +1 -1
  60. package/dist/src/tooltip/refseqGeneTooltipHandler.js +1 -1
  61. package/dist/src/tooltip/tooltipHandler.d.ts +1 -1
  62. package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -1
  63. package/dist/src/tooltip/tooltipHandler.ts +1 -1
  64. package/dist/src/types/embedApi.d.ts +6 -0
  65. package/dist/src/types/viewContext.d.ts +2 -3
  66. package/dist/src/utils/debounce.d.ts +2 -2
  67. package/dist/src/utils/debounce.d.ts.map +1 -1
  68. package/dist/src/utils/debounce.js +5 -2
  69. package/dist/src/utils/expression.d.ts +2 -2
  70. package/dist/src/utils/expression.d.ts.map +1 -1
  71. package/dist/src/utils/expression.js +1 -1
  72. package/dist/src/utils/formatObject.d.ts +2 -2
  73. package/dist/src/utils/formatObject.d.ts.map +1 -1
  74. package/dist/src/utils/formatObject.js +2 -2
  75. package/dist/src/utils/inputBinding.d.ts +5 -0
  76. package/dist/src/utils/inputBinding.d.ts.map +1 -0
  77. package/dist/src/utils/inputBinding.js +115 -0
  78. package/dist/src/utils/ui/tooltip.js +1 -1
  79. package/dist/src/view/paramMediator.d.ts +108 -0
  80. package/dist/src/view/paramMediator.d.ts.map +1 -0
  81. package/dist/src/view/paramMediator.js +337 -0
  82. package/dist/src/view/paramMediator.test.js +211 -0
  83. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  84. package/dist/src/view/scaleResolution.js +11 -6
  85. package/dist/src/view/view.d.ts +4 -1
  86. package/dist/src/view/view.d.ts.map +1 -1
  87. package/dist/src/view/view.js +19 -5
  88. package/dist/src/view/viewFactory.d.ts.map +1 -1
  89. package/dist/src/view/viewFactory.js +45 -0
  90. package/dist/src/view/viewUtils.d.ts +5 -1
  91. package/dist/src/view/viewUtils.d.ts.map +1 -1
  92. package/dist/src/view/viewUtils.js +9 -4
  93. package/package.json +16 -17
  94. package/dist/src/paramBroker.d.ts +0 -46
  95. package/dist/src/paramBroker.d.ts.map +0 -1
  96. package/dist/src/paramBroker.js +0 -118
@@ -1,6 +1,14 @@
1
- const css = `.genome-spy {
1
+ const css = `
2
+ .genome-spy {
2
3
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
3
4
  position: relative;
5
+ display: flex;
6
+ flex-direction: column;
7
+ }
8
+ .genome-spy .canvas-wrapper {
9
+ position: relative;
10
+ flex-grow: 1;
11
+ overflow: hidden;
4
12
  }
5
13
  .genome-spy canvas {
6
14
  transform: scale(1, 1);
@@ -19,14 +27,14 @@ const css = `.genome-spy {
19
27
  opacity: 0;
20
28
  transition: opacity 0.7s;
21
29
  }
22
- .genome-spy.loading canvas {
30
+ .genome-spy .loading > canvas {
23
31
  transform: scale(0.95, 0.95);
24
32
  opacity: 0;
25
33
  }
26
- .genome-spy.loading .loading-message .message {
34
+ .genome-spy .loading > .loading-message .message {
27
35
  opacity: 1;
28
36
  }
29
- .genome-spy.loading .ellipsis {
37
+ .genome-spy .loading > .loading-message .message .ellipsis {
30
38
  animation: blinker 1s linear infinite;
31
39
  }
32
40
  @keyframes blinker {
@@ -138,6 +146,45 @@ const css = `.genome-spy {
138
146
  border: 1px solid red;
139
147
  padding: 10px;
140
148
  background: #fff0f0;
141
- }`;
149
+ }
150
+
151
+ .gs-input-binding {
152
+ display: grid;
153
+ grid-template-columns: max-content max-content;
154
+ column-gap: 1em;
155
+ row-gap: 0.3em;
156
+ justify-items: start;
157
+ }
158
+ .gs-input-binding > select,
159
+ .gs-input-binding > input:not([type=checkbox]) {
160
+ width: 100%;
161
+ }
162
+ .gs-input-binding input[type=range] + span {
163
+ display: inline-block;
164
+ margin-left: 0.3em;
165
+ min-width: 2.2em;
166
+ font-variant-numeric: tabular-nums;
167
+ }
168
+ .gs-input-binding input[type=range],
169
+ .gs-input-binding input[type=radio] {
170
+ vertical-align: text-bottom;
171
+ }
172
+ .gs-input-binding .radio-group {
173
+ display: flex;
174
+ align-items: center;
175
+ }
176
+ .gs-input-binding .description {
177
+ max-width: 26em;
178
+ grid-column: 1/-1;
179
+ color: #777;
180
+ font-size: 90%;
181
+ margin-top: -0.5em;
182
+ }
142
183
 
184
+ .gs-input-bindings {
185
+ flex-basis: content;
186
+ font-size: 14px;
187
+ padding: 10px;
188
+ }
189
+ `;
143
190
  export default css;
@@ -10,6 +10,15 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
10
10
 
11
11
  position: relative;
12
12
 
13
+ display: flex;
14
+ flex-direction: column;
15
+
16
+ .canvas-wrapper {
17
+ position: relative;
18
+ flex-grow: 1;
19
+ overflow: hidden;
20
+ }
21
+
13
22
  canvas {
14
23
  transform: scale(1, 1);
15
24
  opacity: 1;
@@ -31,23 +40,23 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
31
40
  }
32
41
  }
33
42
 
34
- &.loading {
35
- canvas {
43
+ .loading {
44
+ > canvas {
36
45
  transform: scale(0.95, 0.95);
37
46
  opacity: 0;
38
47
  }
39
48
 
40
- .loading-message .message {
49
+ > .loading-message .message {
41
50
  opacity: 1;
42
- }
43
51
 
44
- .ellipsis {
45
- animation: blinker 1s linear infinite;
46
- }
52
+ .ellipsis {
53
+ animation: blinker 1s linear infinite;
54
+ }
47
55
 
48
- @keyframes blinker {
49
- 50% {
50
- opacity: 0;
56
+ @keyframes blinker {
57
+ 50% {
58
+ opacity: 0;
59
+ }
51
60
  }
52
61
  }
53
62
  }
@@ -187,3 +196,47 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
187
196
  }
188
197
  }
189
198
  }
199
+
200
+ .gs-input-binding {
201
+ display: grid;
202
+ grid-template-columns: max-content max-content;
203
+ column-gap: 1em;
204
+ row-gap: 0.3em;
205
+ justify-items: start;
206
+
207
+ > select,
208
+ > input:not([type="checkbox"]) {
209
+ width: 100%;
210
+ }
211
+
212
+ input[type="range"] + span {
213
+ display: inline-block;
214
+ margin-left: 0.3em;
215
+ min-width: 2.2em;
216
+ font-variant-numeric: tabular-nums;
217
+ }
218
+
219
+ input[type="range"],
220
+ input[type="radio"] {
221
+ vertical-align: text-bottom;
222
+ }
223
+
224
+ .radio-group {
225
+ display: flex;
226
+ align-items: center;
227
+ }
228
+
229
+ .description {
230
+ max-width: 26em;
231
+ grid-column: 1 / -1;
232
+ color: #777;
233
+ font-size: 90%;
234
+ margin-top: -0.5em;
235
+ }
236
+ }
237
+
238
+ .gs-input-bindings {
239
+ flex-basis: content;
240
+ font-size: 14px;
241
+ padding: $basic-spacing;
242
+ }
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ echo "const css = \`" > genome-spy.css.js
3
+ sass genome-spy.scss >> genome-spy.css.js
4
+ echo "\`;" >> genome-spy.css.js
5
+ echo "export default css;" >> genome-spy.css.js
6
+
@@ -1,4 +1,4 @@
1
- import { html } from "lit-html";
1
+ import { html } from "lit";
2
2
  import formatObject from "../utils/formatObject.js";
3
3
 
4
4
  /**
@@ -1,5 +1,5 @@
1
1
  import { debounce } from "../utils/debounce.js";
2
- import { html } from "lit-html";
2
+ import { html } from "lit";
3
3
 
4
4
  /*
5
5
  * https://www.ncbi.nlm.nih.gov/books/NBK25500/
@@ -1,4 +1,4 @@
1
- import { TemplateResult } from "lit-html";
1
+ import { TemplateResult } from "lit";
2
2
  import Mark from "../marks/mark.js";
3
3
  /**
4
4
  * Converts a datum to tooltip (HTMLElement or lit's TemplateResult).
@@ -1 +1 @@
1
- {"version":3,"file":"tooltipHandler.d.ts","sourceRoot":"","sources":["../../../src/tooltip/tooltipHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,IAAI,MAAM,kBAAkB,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,IAAI,EAAE,IAAI;AACV,sDAAsD;AACtD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC3B,OAAO,CAAC,MAAM,GAAG,cAAc,GAAG,WAAW,CAAC,CAAC"}
1
+ {"version":3,"file":"tooltipHandler.d.ts","sourceRoot":"","sources":["../../../src/tooltip/tooltipHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,IAAI,MAAM,kBAAkB,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,IAAI,EAAE,IAAI;AACV,sDAAsD;AACtD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC3B,OAAO,CAAC,MAAM,GAAG,cAAc,GAAG,WAAW,CAAC,CAAC"}
@@ -1,4 +1,4 @@
1
- import { TemplateResult } from "lit-html";
1
+ import { TemplateResult } from "lit";
2
2
  import Mark from "../marks/mark.js";
3
3
 
4
4
  /**
@@ -27,6 +27,12 @@ export interface EmbedOptions {
27
27
  * Custom tooltip handlers. Use `"default"` to override the default handler
28
28
  */
29
29
  tooltipHandlers?: Record<string, TooltipHandler>;
30
+
31
+ /**
32
+ * Where to put the input binding elements. The default is `"default"`, which means that
33
+ * the input binding elements are placed in the same container as the GenomeSpy instance.
34
+ */
35
+ inputBindingContainer?: HTMLElement | "none" | "default";
30
36
  }
31
37
 
32
38
  /**
@@ -1,4 +1,4 @@
1
- import { TemplateResult } from "lit-html";
1
+ import { TemplateResult } from "lit";
2
2
  import View, { BroadcastMessage } from "../view/view.js";
3
3
  import DataFlow from "../data/dataFlow.js";
4
4
  import AccessorFactory from "../encoder/accessor.js";
@@ -11,7 +11,7 @@ import { Datum } from "../data/flowNode.js";
11
11
  import { ImportSpec, ViewSpec } from "../spec/view.js";
12
12
  import ContainerView from "./containerView.js";
13
13
  import { BroadcastEventType } from "../genomeSpy.js";
14
- import ParamBroker from "../paramBroker.js";
14
+ import ParamMediator from "../view/paramMediator.js";
15
15
 
16
16
  export interface Hover {
17
17
  mark: Mark;
@@ -29,7 +29,6 @@ export default interface ViewContext {
29
29
  genomeStore?: GenomeStore;
30
30
  fontManager: BmFontManager;
31
31
 
32
- paramBroker: ParamBroker;
33
32
  devicePixelRatio: number;
34
33
 
35
34
  requestLayoutReflow: () => void;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @param {(...args:T) => R} func
3
- * @param {number} wait
3
+ * @param {number | (() => number)} wait
4
4
  * @template {any[]} T
5
5
  * @template R
6
6
  */
7
- export function debounce<T extends any[], R>(func: (...args: T) => R, wait: number, rejectOnDebounce?: boolean): (...args: T) => Promise<R>;
7
+ export function debounce<T extends any[], R>(func: (...args: T) => R, wait: number | (() => number), rejectOnDebounce?: boolean): (...args: T) => Promise<R>;
8
8
  //# sourceMappingURL=debounce.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"debounce.d.ts","sourceRoot":"","sources":["../../../src/utils/debounce.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,4EAJW,MAAM,0DAkChB"}
1
+ {"version":3,"file":"debounce.d.ts","sourceRoot":"","sources":["../../../src/utils/debounce.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,4EAJW,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,0DAqCjC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @param {(...args:T) => R} func
3
- * @param {number} wait
3
+ * @param {number | (() => number)} wait
4
4
  * @template {any[]} T
5
5
  * @template R
6
6
  */
@@ -29,7 +29,10 @@ export function debounce(func, wait, rejectOnDebounce = true) {
29
29
  clearTimeout(timeout);
30
30
 
31
31
  rejectPrevious = reject;
32
- timeout = window.setTimeout(later, wait);
32
+ timeout = window.setTimeout(
33
+ later,
34
+ typeof wait == "function" ? wait() : wait
35
+ );
33
36
  });
34
37
  };
35
38
 
@@ -4,7 +4,7 @@
4
4
  * @prop { string[] } globals
5
5
  * @prop { string } code
6
6
  *
7
- * @typedef { ((datum: object) => any) & ExpressionProps } ExpressionFunction
7
+ * @typedef { ((datum?: object) => any) & ExpressionProps } ExpressionFunction
8
8
  *
9
9
  * @param {string} expr
10
10
  * @returns {ExpressionFunction}
@@ -15,5 +15,5 @@ export type ExpressionProps = {
15
15
  globals: string[];
16
16
  code: string;
17
17
  };
18
- export type ExpressionFunction = ((datum: object) => any) & ExpressionProps;
18
+ export type ExpressionFunction = ((datum?: object) => any) & ExpressionProps;
19
19
  //# sourceMappingURL=expression.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../../src/utils/expression.js"],"names":[],"mappings":"AAyDA;;;;;;;;;;GAUG;AACH,6CAHW,MAAM,sBACJ,kBAAkB,CAyB9B;;YAhCU,MAAM,EAAE;aACR,MAAM,EAAE;UACR,MAAM;;0CAEM,MAAM,KAAK,GAAG"}
1
+ {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../../src/utils/expression.js"],"names":[],"mappings":"AAyDA;;;;;;;;;;GAUG;AACH,6CAHW,MAAM,sBACJ,kBAAkB,CAyB9B;;YAhCU,MAAM,EAAE;aACR,MAAM,EAAE;UACR,MAAM;;2CAEO,MAAM,KAAK,GAAG"}
@@ -61,7 +61,7 @@ const cg = codegenExpression({
61
61
  * @prop { string[] } globals
62
62
  * @prop { string } code
63
63
  *
64
- * @typedef { ((datum: object) => any) & ExpressionProps } ExpressionFunction
64
+ * @typedef { ((datum?: object) => any) & ExpressionProps } ExpressionFunction
65
65
  *
66
66
  * @param {string} expr
67
67
  * @returns {ExpressionFunction}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  *
3
3
  * @param {any} object Object to format
4
- * @returns {string | import("lit-html").TemplateResult}
4
+ * @returns {string | import("lit").TemplateResult}
5
5
  */
6
- export default function formatObject(object: any): string | import("lit-html").TemplateResult;
6
+ export default function formatObject(object: any): string | import("lit").TemplateResult;
7
7
  //# sourceMappingURL=formatObject.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatObject.d.ts","sourceRoot":"","sources":["../../../src/utils/formatObject.js"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,6CAHW,GAAG,GACD,MAAM,GAAG,OAAO,UAAU,EAAE,cAAc,CA0BtD"}
1
+ {"version":3,"file":"formatObject.d.ts","sourceRoot":"","sources":["../../../src/utils/formatObject.js"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,6CAHW,GAAG,GACD,MAAM,GAAG,OAAO,KAAK,EAAE,cAAc,CA0BjD"}
@@ -1,6 +1,6 @@
1
1
  import { isNumber, isString, isBoolean, isArray } from "vega-util";
2
2
  import { format as d3format } from "d3-format";
3
- import { html, nothing } from "lit-html";
3
+ import { html, nothing } from "lit";
4
4
 
5
5
  const numberFormat = d3format(".4~r");
6
6
  const exponentNumberFormat = d3format(".4~e");
@@ -8,7 +8,7 @@ const exponentNumberFormat = d3format(".4~e");
8
8
  /**
9
9
  *
10
10
  * @param {any} object Object to format
11
- * @returns {string | import("lit-html").TemplateResult}
11
+ * @returns {string | import("lit").TemplateResult}
12
12
  */
13
13
  export default function formatObject(object) {
14
14
  if (object === null || object === undefined) {
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @param {import("../view/paramMediator.js").default} mediator
3
+ */
4
+ export default function createBindingInputs(mediator: import("../view/paramMediator.js").default): import("lit-html").TemplateResult<2 | 1>[];
5
+ //# sourceMappingURL=inputBinding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputBinding.d.ts","sourceRoot":"","sources":["../../../src/utils/inputBinding.js"],"names":[],"mappings":"AAIA;;GAEG;AACH,sDAFW,OAAO,0BAA0B,EAAE,OAAO,8CA6GpD"}
@@ -0,0 +1,115 @@
1
+ import { html } from "lit";
2
+ import { debounce } from "./debounce.js";
3
+ import { tickStep } from "d3-array";
4
+
5
+ /**
6
+ * @param {import("../view/paramMediator.js").default} mediator
7
+ */
8
+ export default function createBindingInputs(mediator) {
9
+ const random = Math.floor(Math.random() * 0xffffff).toString(16);
10
+
11
+ /** @type {import("lit").TemplateResult[]} */
12
+ const inputs = [];
13
+
14
+ for (const param of mediator.paramConfigs.values()) {
15
+ const bind = param.bind;
16
+ if (!bind || !("input" in bind)) {
17
+ continue;
18
+ }
19
+
20
+ const name = param.name;
21
+ const setter = mediator.getSetter(name);
22
+ const value = mediator.getValue(name);
23
+ const label = bind.name ?? name;
24
+
25
+ // TODO: Implement two-way data binding, e.g. when an external agent changes
26
+ // the parameter value, the UI components should be updated.
27
+
28
+ const debouncedSetter = bind.debounce
29
+ ? debounce(setter, bind.debounce, false)
30
+ : setter;
31
+
32
+ const id = `${random}-param-${name}`;
33
+
34
+ if (bind.input == "range") {
35
+ // TODO: Show the value next to the slider
36
+ inputs.push(
37
+ html`<label for=${id}>${label}</label>
38
+ <div>
39
+ <input
40
+ id=${id}
41
+ type="range"
42
+ min=${bind.min ?? 0}
43
+ max=${bind.max ?? 100}
44
+ step=${bind.step ??
45
+ tickStep(bind.min, bind.max, 100)}
46
+ .value=${value}
47
+ @input=${(/** @type {any} */ e) => {
48
+ debouncedSetter(e.target.valueAsNumber);
49
+ e.target.nextElementSibling.textContent =
50
+ e.target.valueAsNumber;
51
+ }}
52
+ /><span>${value}</span>
53
+ </div>`
54
+ );
55
+ } else if (bind.input == "checkbox") {
56
+ inputs.push(
57
+ html`<label for=${id}>${label}</label>
58
+ <input
59
+ id=${id}
60
+ type="checkbox"
61
+ ?checked=${value}
62
+ @input=${(/** @type {any} */ e) =>
63
+ debouncedSetter(e.target.checked)}
64
+ />`
65
+ );
66
+ } else if (bind.input == "radio") {
67
+ inputs.push(
68
+ html`<span class="label">${label}</span>
69
+ <div class="radio-group">
70
+ ${bind.options.map(
71
+ (option, i) => html`<label>
72
+ <input
73
+ type="radio"
74
+ name=${name}
75
+ value=${option}
76
+ .checked=${value == option}
77
+ @input=${(/** @type {any} */ e) =>
78
+ debouncedSetter(e.target.value)}
79
+ />${bind.labels?.[i] ?? option}</label
80
+ >`
81
+ )}
82
+ </div>`
83
+ );
84
+ } else if (bind.input == "select") {
85
+ inputs.push(
86
+ html`<label for=${id}>${label}</label>
87
+ <select
88
+ id=${id}
89
+ @input=${(/** @type {any} */ e) =>
90
+ debouncedSetter(e.target.value)}
91
+ >
92
+ ${bind.options.map(
93
+ (option, i) => html`<option
94
+ value=${option}
95
+ ?selected=${value == option}
96
+ >
97
+ ${bind.labels?.[i] ?? option}
98
+ </option>`
99
+ )}
100
+ </select> `
101
+ );
102
+ } else {
103
+ // TODO: Support other types: "text", "number", "color".
104
+ throw new Error("Unsupported input type: " + bind.input);
105
+ }
106
+
107
+ if (bind.description) {
108
+ inputs.push(
109
+ html`<div class="description">${bind.description}</div>`
110
+ );
111
+ }
112
+ }
113
+
114
+ return inputs;
115
+ }
@@ -1,5 +1,5 @@
1
1
  import clientPoint from "../point.js";
2
- import { html, render } from "lit-html";
2
+ import { html, render } from "lit";
3
3
  import { peek } from "../arrayUtils.js";
4
4
 
5
5
  export const SUPPRESS_TOOLTIP_CLASS_NAME = "gs-suppress-tooltip";
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @param {any} x
3
+ * @returns {x is import("../spec/parameter.js").ExprRef}
4
+ */
5
+ export function isExprRef(x: any): x is import("../spec/parameter.js").ExprRef;
6
+ /**
7
+ * Removes ExprRef from the type and checks that the value is not an ExprRef.
8
+ * This is designed to be used with `activateExprRefProps`.
9
+ *
10
+ * @param {T | import("../spec/parameter.js").ExprRef} x
11
+ * @template T
12
+ * @returns {T}
13
+ */
14
+ export function withoutExprRef<T>(x: T | import("../spec/parameter.js").ExprRef): T;
15
+ /**
16
+ * Takes a record of properties that may have ExprRefs as values. Converts the
17
+ * ExprRefs to getters and setups a listener that is called when any of the
18
+ * expressions (upstream parameters) change.
19
+ *
20
+ * @param {ParamMediator} paramMediator
21
+ * @param {T} props The properties object
22
+ * @param {(props: (keyof T)[]) => void} [listener] Listener to be called when any of the expressions change
23
+ * @returns T
24
+ * @template {Record<string, any | import("../spec/parameter.js").ExprRef>} T
25
+ */
26
+ export function activateExprRefProps<T extends Record<string, any>>(paramMediator: ParamMediator, props: T, listener?: (props: (keyof T)[]) => void): T;
27
+ /**
28
+ * A class that manages parameters and expressions.
29
+ * Supports nesting and scoped parameters.
30
+ *
31
+ * @typedef {import("../utils/expression.js").ExpressionFunction & { addListener: (listener: () => void) => void, invalidate: () => void, identifier: () => string}} ExprRefFunction
32
+ */
33
+ export default class ParamMediator {
34
+ /**
35
+ * @param {() => ParamMediator} [parentFinder]
36
+ * An optional function that returns the parent mediator.
37
+ * N.B. The function must always return the same mediator for the same parent,
38
+ * i.e., the changing the structure of the hierarchy is NOT supported.
39
+ */
40
+ constructor(parentFinder?: () => ParamMediator);
41
+ /**
42
+ * @type {Map<string, Set<() => void>>}
43
+ * @protected
44
+ */
45
+ protected paramListeners: Map<string, Set<() => void>>;
46
+ /**
47
+ * @param {VariableParameter} param
48
+ * @returns {ParameterSetter}
49
+ */
50
+ registerParam(param: import("../spec/parameter.js").VariableParameter): (value: any) => void;
51
+ /**
52
+ *
53
+ * @param {string} paramName
54
+ * @param {T} initialValue
55
+ * @returns {(value: T) => void}
56
+ * @template T
57
+ */
58
+ allocateSetter<T>(paramName: string, initialValue: T): (value: T) => void;
59
+ /**
60
+ * Gets an existing setter for a parameter. Throws if the setter is not found.
61
+ * @param {string} paramName
62
+ */
63
+ getSetter(paramName: string): (value: any) => void;
64
+ /**
65
+ * Get the value of a parameter from this mediator.
66
+ * @param {string} paramName
67
+ */
68
+ getValue(paramName: string): any;
69
+ /**
70
+ * Get the value of a parameter from this mediator or the ancestors.
71
+ * @param {string} paramName
72
+ */
73
+ findValue(paramName: string): any;
74
+ /**
75
+ * Returns configs for all parameters that have been registered using `registerParam`.
76
+ */
77
+ get paramConfigs(): ReadonlyMap<string, import("../spec/parameter.js").VariableParameter>;
78
+ /**
79
+ *
80
+ * @param {string} paramName
81
+ * @returns {ParamMediator}
82
+ * @protected
83
+ */
84
+ protected findMediatorForParam(paramName: string): ParamMediator;
85
+ /**
86
+ * Parse expr and return a function that returns the value of the parameter.
87
+ *
88
+ * @param {string} expr
89
+ */
90
+ createExpression(expr: string): ExprRefFunction;
91
+ /**
92
+ * A convenience method for evaluating an expression.
93
+ *
94
+ * @param {string} expr
95
+ */
96
+ evaluateAndGet(expr: string): any;
97
+ #private;
98
+ }
99
+ /**
100
+ * A class that manages parameters and expressions.
101
+ * Supports nesting and scoped parameters.
102
+ */
103
+ export type ExprRefFunction = ((datum?: object) => any) & import("../utils/expression.js").ExpressionProps & {
104
+ addListener: (listener: () => void) => void;
105
+ invalidate: () => void;
106
+ identifier: () => string;
107
+ };
108
+ //# sourceMappingURL=paramMediator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paramMediator.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.js"],"names":[],"mappings":"AAsQA;;;GAGG;AACH,6BAHW,GAAG,+CAKb;AAED;;;;;;;GAOG;AACH,oFASC;AAED;;;;;;;;;;GAUG;AACH,mFANW,aAAa,+CAEW,IAAI,KAwCtC;AA7UD;;;;;GAKG;AACH;IA2BI;;;;;OAKG;IACH,2BALW,MAAM,aAAa,EAU7B;IA7BD;;;OAGG;IACH,0BAHU,IAAI,MAAM,EAAE,IAAI,MAAM,IAAI,CAAC,CAAC,CAGvB;IA2Bf;;;OAGG;IACH,gFAzCqB,GAAG,KAAK,IAAI,CAkEhC;IAED;;;;;;OAMG;IACH,6BALW,MAAM,kCAEU,IAAI,CA8B9B;IAED;;;OAGG;IACH,qBAFW,MAAM,WA9Fc,GAAG,KAAK,IAAI,CAsG1C;IAED;;;OAGG;IACH,oBAFW,MAAM,OAIhB;IAED;;;OAGG;IACH,qBAFW,MAAM,OAKhB;IAED;;OAEG;IACH,0FAIC;IAED;;;;;OAKG;IACH,0CAJW,MAAM,GACJ,aAAa,CASzB;IAID;;;;OAIG;IACH,uBAFW,MAAM,mBA4EhB;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAKhB;;CACJ;;;;;;4BA7P4F,MAAM,IAAI,KAAK,IAAI;gBAAc,MAAM,IAAI;gBAAc,MAAM,MAAM"}