@vitessce/vit-s 3.1.3 → 3.2.1

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 (49) hide show
  1. package/dist/index.js +1801 -132
  2. package/dist-tsc/data-hook-utils.d.ts +1 -0
  3. package/dist-tsc/data-hook-utils.d.ts.map +1 -1
  4. package/dist-tsc/data-hook-utils.js +12 -4
  5. package/dist-tsc/data-hooks-multilevel-utils.d.ts +77 -0
  6. package/dist-tsc/data-hooks-multilevel-utils.d.ts.map +1 -0
  7. package/dist-tsc/data-hooks-multilevel-utils.js +418 -0
  8. package/dist-tsc/data-hooks-multilevel-utils.test.d.ts +2 -0
  9. package/dist-tsc/data-hooks-multilevel-utils.test.d.ts.map +1 -0
  10. package/dist-tsc/data-hooks-multilevel-utils.test.js +101 -0
  11. package/dist-tsc/data-hooks-multilevel.d.ts +8 -0
  12. package/dist-tsc/data-hooks-multilevel.d.ts.map +1 -0
  13. package/dist-tsc/data-hooks-multilevel.js +125 -0
  14. package/dist-tsc/data-hooks.d.ts +7 -0
  15. package/dist-tsc/data-hooks.d.ts.map +1 -1
  16. package/dist-tsc/data-hooks.js +75 -6
  17. package/dist-tsc/hooks.js +1 -1
  18. package/dist-tsc/index.d.ts +3 -2
  19. package/dist-tsc/index.js +3 -2
  20. package/dist-tsc/shared-mui/components.d.ts.map +1 -1
  21. package/dist-tsc/shared-mui/components.js +3 -2
  22. package/dist-tsc/shared-plot-options/CellColorEncodingOption.d.ts.map +1 -1
  23. package/dist-tsc/shared-plot-options/CellColorEncodingOption.js +2 -1
  24. package/dist-tsc/state/hooks.d.ts +80 -21
  25. package/dist-tsc/state/hooks.d.ts.map +1 -1
  26. package/dist-tsc/state/hooks.js +428 -103
  27. package/dist-tsc/state/hooks.test.d.ts +2 -0
  28. package/dist-tsc/state/hooks.test.d.ts.map +1 -0
  29. package/dist-tsc/state/hooks.test.js +149 -0
  30. package/dist-tsc/state/spatial-reducers.d.ts +25 -0
  31. package/dist-tsc/state/spatial-reducers.d.ts.map +1 -0
  32. package/dist-tsc/state/spatial-reducers.js +251 -0
  33. package/dist-tsc/state/spatial-reducers.test.d.ts +2 -0
  34. package/dist-tsc/state/spatial-reducers.test.d.ts.map +1 -0
  35. package/dist-tsc/state/spatial-reducers.test.js +1382 -0
  36. package/package.json +6 -5
  37. package/src/data-hook-utils.js +19 -3
  38. package/src/data-hooks-multilevel-utils.js +571 -0
  39. package/src/data-hooks-multilevel-utils.test.js +110 -0
  40. package/src/data-hooks-multilevel.js +226 -0
  41. package/src/data-hooks.js +156 -6
  42. package/src/hooks.js +1 -1
  43. package/src/index.js +25 -0
  44. package/src/shared-mui/components.js +9 -4
  45. package/src/shared-plot-options/CellColorEncodingOption.js +2 -1
  46. package/src/state/hooks.js +485 -104
  47. package/src/state/hooks.test.js +182 -0
  48. package/src/state/spatial-reducers.js +291 -0
  49. package/src/state/spatial-reducers.test.js +1432 -0
@@ -0,0 +1,182 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ getParameterScope,
4
+ getParameterScopeBy,
5
+ getScopes,
6
+ getScopesBy,
7
+ } from './hooks.js';
8
+
9
+ describe('vit-s/state/hooks.js', () => {
10
+ describe('getParameterScope', () => {
11
+ it('works', () => {
12
+ expect(getParameterScope(
13
+ 'obsType',
14
+ {
15
+ obsType: 'A',
16
+ },
17
+ )).toEqual('A');
18
+ });
19
+ });
20
+ describe('getParameterScopeBy', () => {
21
+ it('works', () => {
22
+ expect(getParameterScopeBy(
23
+ 'spatialTargetC',
24
+ 'spatialSegmentationLayer',
25
+ 'glomerulus',
26
+ {
27
+ spatialSegmentationLayer: ['glomerulus', 'tubule'],
28
+ },
29
+ {
30
+ spatialSegmentationLayer: {
31
+ spatialTargetC: {
32
+ glomerulus: 'A',
33
+ tubule: 'B',
34
+ },
35
+ },
36
+ },
37
+ {
38
+ spatialSegmentationLayer: {
39
+ glomerulus: 'glomerulus',
40
+ tubule: 'tubule',
41
+ },
42
+ spatialTargetC: {
43
+ A: 1,
44
+ B: 2,
45
+ },
46
+ },
47
+ )).toEqual('A');
48
+ });
49
+ });
50
+ describe('getScopes', () => {
51
+ it('works without metaCoordinationScopes', () => {
52
+ expect(getScopes(
53
+ {
54
+ obsType: 'A',
55
+ },
56
+ null,
57
+ )).toEqual({
58
+ obsType: 'A',
59
+ });
60
+ });
61
+ it('works with one metaCoordinationScopes', () => {
62
+ expect(getScopes(
63
+ {
64
+ // meta match should take precedence
65
+ metaCoordinationScopes: 'metaA',
66
+ obsType: 'A',
67
+ },
68
+ {
69
+ metaA: {
70
+ obsType: 'B',
71
+ },
72
+ },
73
+ )).toEqual({
74
+ // meta match should take precedence
75
+ metaCoordinationScopes: 'metaA',
76
+ obsType: 'B',
77
+ });
78
+ });
79
+ it('works with multiple metaCoordinationScopes', () => {
80
+ expect(getScopes(
81
+ {
82
+ // first meta match should take precedence
83
+ metaCoordinationScopes: ['metaA', 'metaB'],
84
+ obsType: 'A',
85
+ },
86
+ {
87
+ metaA: {
88
+ featureType: 'D',
89
+ },
90
+ metaB: {
91
+ obsType: 'C',
92
+ },
93
+ },
94
+ )).toEqual({
95
+ // first meta match should take precedence
96
+ metaCoordinationScopes: ['metaA', 'metaB'],
97
+ featureType: 'D',
98
+ obsType: 'C',
99
+ });
100
+ });
101
+ });
102
+ describe('getScopesBy', () => {
103
+ it('works with one metaCoordinationScopesBy', () => {
104
+ expect(getScopesBy(
105
+ {
106
+ metaCoordinationScopesBy: 'metaA',
107
+ spatialSegmentationLayer: ['abc', 'def'],
108
+ },
109
+ {
110
+ spatialSegmentationLayer: {
111
+ spatialTargetC: {
112
+ glomerulus: 'ghi',
113
+ tubule: 'jkl',
114
+ },
115
+ },
116
+ },
117
+ {
118
+ metaA: {
119
+ spatialSegmentationLayer: {
120
+ spatialTargetC: {
121
+ glomerulus: 'A',
122
+ tubule: 'B',
123
+ },
124
+ },
125
+ },
126
+ },
127
+ )).toEqual({
128
+ spatialSegmentationLayer: {
129
+ spatialTargetC: {
130
+ glomerulus: 'A',
131
+ tubule: 'B',
132
+ },
133
+ },
134
+ });
135
+ });
136
+ it('works with multiple metaCoordinationScopes', () => {
137
+ expect(getScopesBy(
138
+ {
139
+ metaCoordinationScopesBy: ['metaA', 'metaB'],
140
+ spatialSegmentationLayer: ['abc', 'def'],
141
+ },
142
+ {
143
+ spatialSegmentationLayer: {
144
+ spatialTargetC: {
145
+ glomerulus: 'ghi',
146
+ tubule: 'jkl',
147
+ },
148
+ },
149
+ },
150
+ {
151
+ metaA: {
152
+ spatialSegmentationLayer: {
153
+ spatialLayerOpacity: {
154
+ glomerulus: 'C',
155
+ tubule: 'D',
156
+ },
157
+ },
158
+ },
159
+ metaB: {
160
+ spatialSegmentationLayer: {
161
+ spatialTargetC: {
162
+ glomerulus: 'A',
163
+ tubule: 'B',
164
+ },
165
+ },
166
+ },
167
+ },
168
+ )).toEqual({
169
+ spatialSegmentationLayer: {
170
+ spatialLayerOpacity: {
171
+ glomerulus: 'C',
172
+ tubule: 'D',
173
+ },
174
+ spatialTargetC: {
175
+ glomerulus: 'A',
176
+ tubule: 'B',
177
+ },
178
+ },
179
+ });
180
+ });
181
+ });
182
+ });
@@ -0,0 +1,291 @@
1
+ /* eslint-disable max-len */
2
+ import { getNextScope } from '@vitessce/utils';
3
+ import { CoordinationType } from '@vitessce/constants-internal';
4
+
5
+ /**
6
+ * Get the name of the metaCoordinationScopes coordination scope
7
+ * for a particular non-meta coordination scope, after accounting for
8
+ * meta-coordination.
9
+ * @param {*} coordinationScopes The coordinationScopes for a view.
10
+ * @param {*} coordinationSpace The coordinationSpace for a config.
11
+ * @param {string} parameter The parameter for which to get the metaScope.
12
+ * @returns {string|undefined} The metaCoordinationScopes coordination scope name.
13
+ */
14
+ export function getMetaScope(coordinationScopes, coordinationSpace, parameter) {
15
+ let latestMetaScope;
16
+ // Check if there is a matching meta-scope.
17
+ if (coordinationSpace) {
18
+ // Determine if there is a meta-scope that would take precedence.
19
+ const metaScopes = coordinationScopes[CoordinationType.META_COORDINATION_SCOPES];
20
+ const metaSpace = coordinationSpace[CoordinationType.META_COORDINATION_SCOPES];
21
+ if (metaScopes && metaSpace) {
22
+ // The view.coordinationScopes.metaCoordinationScopes might be an array or a string.
23
+ // Convert to an array.
24
+ const metaScopesArr = Array.isArray(metaScopes) ? metaScopes : [metaScopes];
25
+ metaScopesArr.forEach((metaScope) => {
26
+ // Merge the original coordinationScopes with the matching meta-coordinationScopes
27
+ // from the coordinationSpace.
28
+ if (metaSpace[metaScope][parameter]) {
29
+ latestMetaScope = metaScope;
30
+ }
31
+ });
32
+ }
33
+ }
34
+ return latestMetaScope;
35
+ }
36
+
37
+ /**
38
+ * Get the name of the metaCoordinationScopesBy coordination scope
39
+ * for a particular non-meta coordination scope, after accounting for
40
+ * meta-coordination.
41
+ * @param {*} coordinationScopes The coordinationScopes for a view.
42
+ * @param {*} coordinationSpace The coordinationSpace for a config.
43
+ * @param {string} byParameter The byParameter for which to get the metaScope.
44
+ * @param {string} parameter The parameter for which to get the metaScope.
45
+ * @param {string} byScope The byScope for the byParameter in which to look for the metaScope.
46
+ * @returns {string|undefined} The metaCoordinationScopesBy coordination scope name.
47
+ */
48
+ export function getMetaScopeBy(coordinationScopes, coordinationSpace, byParameter, parameter, byScope) {
49
+ let latestMetaScope;
50
+ // Check if there is a matching meta-scope.
51
+ if (coordinationSpace) {
52
+ // Determine if there is a meta-scope that would take precedence.
53
+ const metaScopesBy = coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY];
54
+ const metaSpaceBy = coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY];
55
+ if (metaSpaceBy && metaScopesBy) {
56
+ // The view.coordinationScopes.metaCoordinationScopes might be an array or a string.
57
+ // Convert to an array.
58
+ const metaScopesArr = Array.isArray(metaScopesBy) ? metaScopesBy : [metaScopesBy];
59
+ metaScopesArr.forEach((metaScope) => {
60
+ // Merge the original coordinationScopesBy with the matching meta-coordinationScopesBy
61
+ // from the coordinationSpace.
62
+ if (metaSpaceBy[metaScope]?.[byParameter]?.[parameter]?.[byScope]) {
63
+ latestMetaScope = metaScope;
64
+ }
65
+ });
66
+ }
67
+ }
68
+ return latestMetaScope;
69
+ }
70
+
71
+
72
+ export function removeImageChannelInMetaCoordinationScopesHelper(coordinationScopesRaw, layerScope, channelScope, coordinationSpace) {
73
+ const metaCoordinationScopes = coordinationSpace[CoordinationType.META_COORDINATION_SCOPES];
74
+ const metaCoordinationScopesBy = coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY];
75
+
76
+ let newMetaCoordinationScopes = metaCoordinationScopes;
77
+ let newMetaCoordinationScopesBy = metaCoordinationScopesBy;
78
+
79
+ // const layerMetaScope = getMetaScope(coordinationScopesRaw, coordinationSpace, CoordinationType.IMAGE_LAYER);
80
+ const channelMetaScopeBy = getMetaScopeBy(
81
+ coordinationScopesRaw,
82
+ coordinationSpace,
83
+ CoordinationType.IMAGE_LAYER,
84
+ CoordinationType.IMAGE_CHANNEL,
85
+ layerScope,
86
+ );
87
+ // Only used in fallback case.
88
+ const channelMetaScope = getMetaScope(coordinationScopesRaw, coordinationSpace, CoordinationType.IMAGE_CHANNEL);
89
+ const hasPerLayerChannels = !!channelMetaScopeBy;
90
+
91
+ const prevChannels = hasPerLayerChannels
92
+ ? metaCoordinationScopesBy // Per-layer channels case.
93
+ ?.[channelMetaScopeBy]
94
+ ?.[CoordinationType.IMAGE_LAYER]
95
+ ?.[CoordinationType.IMAGE_CHANNEL]
96
+ ?.[layerScope]
97
+ : metaCoordinationScopes // Fallback case.
98
+ ?.[channelMetaScope]
99
+ ?.[CoordinationType.IMAGE_CHANNEL];
100
+
101
+ const nextChannels = prevChannels.filter(channel => channel !== channelScope);
102
+
103
+ if (hasPerLayerChannels) {
104
+ newMetaCoordinationScopesBy = {
105
+ ...metaCoordinationScopesBy,
106
+ [channelMetaScopeBy]: {
107
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy],
108
+ [CoordinationType.IMAGE_LAYER]: {
109
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_LAYER],
110
+ [CoordinationType.IMAGE_CHANNEL]: {
111
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_LAYER]?.[CoordinationType.IMAGE_CHANNEL],
112
+ [layerScope]: nextChannels,
113
+ },
114
+ },
115
+ },
116
+ };
117
+ } else {
118
+ newMetaCoordinationScopes = {
119
+ ...metaCoordinationScopes,
120
+ [channelMetaScope]: {
121
+ ...metaCoordinationScopes?.[channelMetaScope],
122
+ [CoordinationType.IMAGE_CHANNEL]: nextChannels,
123
+ },
124
+ };
125
+ }
126
+
127
+ return {
128
+ ...coordinationSpace,
129
+ [CoordinationType.META_COORDINATION_SCOPES]: newMetaCoordinationScopes,
130
+ [CoordinationType.META_COORDINATION_SCOPES_BY]: newMetaCoordinationScopesBy,
131
+ };
132
+ }
133
+
134
+ export function addImageChannelInMetaCoordinationScopesHelper(coordinationScopesRaw, layerScope, coordinationSpace) {
135
+ const metaCoordinationScopes = coordinationSpace[CoordinationType.META_COORDINATION_SCOPES];
136
+ const metaCoordinationScopesBy = coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY];
137
+
138
+ let newMetaCoordinationScopes = metaCoordinationScopes;
139
+ let newMetaCoordinationScopesBy = metaCoordinationScopesBy;
140
+
141
+ // const layerMetaScope = getMetaScope(coordinationScopesRaw, coordinationSpace, CoordinationType.IMAGE_LAYER);
142
+ const channelMetaScopeBy = getMetaScopeBy(
143
+ coordinationScopesRaw,
144
+ coordinationSpace,
145
+ CoordinationType.IMAGE_LAYER,
146
+ CoordinationType.IMAGE_CHANNEL,
147
+ layerScope,
148
+ );
149
+
150
+ // Only used in fallback case.
151
+ const channelMetaScope = getMetaScope(coordinationScopesRaw, coordinationSpace, CoordinationType.IMAGE_CHANNEL);
152
+ const hasPerLayerChannels = !!channelMetaScopeBy;
153
+
154
+ const prevChannels = hasPerLayerChannels
155
+ ? metaCoordinationScopesBy // Per-layer channels case.
156
+ ?.[channelMetaScopeBy]
157
+ ?.[CoordinationType.IMAGE_LAYER]
158
+ ?.[CoordinationType.IMAGE_CHANNEL]
159
+ ?.[layerScope]
160
+ : metaCoordinationScopes // Fallback case.
161
+ ?.[channelMetaScope]
162
+ ?.[CoordinationType.IMAGE_CHANNEL];
163
+
164
+ const allPrevChannelScopes = Object.keys(coordinationSpace[CoordinationType.IMAGE_CHANNEL] || {});
165
+ const nextChannelScope = getNextScope(allPrevChannelScopes);
166
+ const nextChannels = [...prevChannels, nextChannelScope];
167
+
168
+ // Create scope for new channel in coordination space (with dummy initial value). Also,
169
+ // - Create scopes for channel's spatialTargetC, color, window, and opacity (with initial values).
170
+ // - map channelScope to spatialTargetC, color, window, and opacity in metaCoordinationScopesBy.
171
+
172
+ let newCoordinationSpace = coordinationSpace;
173
+
174
+ const nextTargetCScope = getNextScope(Object.keys(coordinationSpace[CoordinationType.SPATIAL_TARGET_C] || {}));
175
+ const nextColorScope = getNextScope(Object.keys(coordinationSpace[CoordinationType.SPATIAL_CHANNEL_COLOR] || {}));
176
+ const nextWindowScope = getNextScope(Object.keys(coordinationSpace[CoordinationType.SPATIAL_CHANNEL_WINDOW] || {}));
177
+ const nextVisibleScope = getNextScope(Object.keys(coordinationSpace[CoordinationType.SPATIAL_CHANNEL_VISIBLE] || {}));
178
+ const nextOpacityScope = getNextScope(Object.keys(coordinationSpace[CoordinationType.SPATIAL_CHANNEL_OPACITY] || {}));
179
+
180
+ newCoordinationSpace = {
181
+ ...coordinationSpace,
182
+ [CoordinationType.IMAGE_CHANNEL]: {
183
+ ...coordinationSpace[CoordinationType.IMAGE_CHANNEL],
184
+ [nextChannelScope]: '__dummy__',
185
+ },
186
+ [CoordinationType.SPATIAL_TARGET_C]: {
187
+ ...coordinationSpace[CoordinationType.SPATIAL_TARGET_C],
188
+ [nextTargetCScope]: 0, // TODO: Use the default values for each coordination type.
189
+ },
190
+ [CoordinationType.SPATIAL_CHANNEL_COLOR]: {
191
+ ...coordinationSpace[CoordinationType.SPATIAL_CHANNEL_COLOR],
192
+ [nextColorScope]: [255, 255, 255],
193
+ },
194
+ [CoordinationType.SPATIAL_CHANNEL_WINDOW]: {
195
+ ...coordinationSpace[CoordinationType.SPATIAL_CHANNEL_WINDOW],
196
+ [nextWindowScope]: [0, 255],
197
+ },
198
+ [CoordinationType.SPATIAL_CHANNEL_VISIBLE]: {
199
+ ...coordinationSpace[CoordinationType.SPATIAL_CHANNEL_VISIBLE],
200
+ [nextVisibleScope]: true,
201
+ },
202
+ [CoordinationType.SPATIAL_CHANNEL_OPACITY]: {
203
+ ...coordinationSpace[CoordinationType.SPATIAL_CHANNEL_OPACITY],
204
+ [nextOpacityScope]: 1,
205
+ },
206
+ };
207
+
208
+ if (hasPerLayerChannels) {
209
+ // Per-layer channels case.
210
+ newMetaCoordinationScopesBy = {
211
+ ...metaCoordinationScopesBy,
212
+ [channelMetaScopeBy]: {
213
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy],
214
+ [CoordinationType.IMAGE_LAYER]: {
215
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_LAYER],
216
+ [CoordinationType.IMAGE_CHANNEL]: {
217
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_LAYER]?.[CoordinationType.IMAGE_CHANNEL],
218
+ [layerScope]: nextChannels,
219
+ },
220
+ },
221
+ [CoordinationType.IMAGE_CHANNEL]: {
222
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_CHANNEL],
223
+ [CoordinationType.SPATIAL_TARGET_C]: {
224
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_TARGET_C],
225
+ [nextChannelScope]: nextTargetCScope,
226
+ },
227
+ [CoordinationType.SPATIAL_CHANNEL_COLOR]: {
228
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_CHANNEL_COLOR],
229
+ [nextChannelScope]: nextColorScope,
230
+ },
231
+ [CoordinationType.SPATIAL_CHANNEL_WINDOW]: {
232
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_CHANNEL_WINDOW],
233
+ [nextChannelScope]: nextWindowScope,
234
+ },
235
+ [CoordinationType.SPATIAL_CHANNEL_VISIBLE]: {
236
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_CHANNEL_VISIBLE],
237
+ [nextChannelScope]: nextVisibleScope,
238
+ },
239
+ [CoordinationType.SPATIAL_CHANNEL_OPACITY]: {
240
+ ...metaCoordinationScopesBy?.[channelMetaScopeBy]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_CHANNEL_OPACITY],
241
+ [nextChannelScope]: nextOpacityScope,
242
+ },
243
+ },
244
+ },
245
+ };
246
+ } else {
247
+ // Fallback case.
248
+ newMetaCoordinationScopes = {
249
+ ...metaCoordinationScopes,
250
+ [channelMetaScope]: {
251
+ ...metaCoordinationScopes?.[channelMetaScope],
252
+ [CoordinationType.IMAGE_CHANNEL]: nextChannels,
253
+ },
254
+ };
255
+ newMetaCoordinationScopesBy = {
256
+ ...metaCoordinationScopesBy,
257
+ [channelMetaScope]: {
258
+ ...metaCoordinationScopesBy?.[channelMetaScope],
259
+ [CoordinationType.IMAGE_CHANNEL]: {
260
+ ...metaCoordinationScopesBy?.[channelMetaScope]?.[CoordinationType.IMAGE_CHANNEL],
261
+ [CoordinationType.SPATIAL_TARGET_C]: {
262
+ ...metaCoordinationScopesBy?.[channelMetaScope]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_TARGET_C],
263
+ [nextChannelScope]: nextTargetCScope,
264
+ },
265
+ [CoordinationType.SPATIAL_CHANNEL_COLOR]: {
266
+ ...metaCoordinationScopesBy?.[channelMetaScope]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_CHANNEL_COLOR],
267
+ [nextChannelScope]: nextColorScope,
268
+ },
269
+ [CoordinationType.SPATIAL_CHANNEL_WINDOW]: {
270
+ ...metaCoordinationScopesBy?.[channelMetaScope]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_CHANNEL_WINDOW],
271
+ [nextChannelScope]: nextWindowScope,
272
+ },
273
+ [CoordinationType.SPATIAL_CHANNEL_VISIBLE]: {
274
+ ...metaCoordinationScopesBy?.[channelMetaScope]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_CHANNEL_VISIBLE],
275
+ [nextChannelScope]: nextVisibleScope,
276
+ },
277
+ [CoordinationType.SPATIAL_CHANNEL_OPACITY]: {
278
+ ...metaCoordinationScopesBy?.[channelMetaScope]?.[CoordinationType.IMAGE_CHANNEL]?.[CoordinationType.SPATIAL_CHANNEL_OPACITY],
279
+ [nextChannelScope]: nextOpacityScope,
280
+ },
281
+ },
282
+ },
283
+ };
284
+ }
285
+
286
+ return {
287
+ ...newCoordinationSpace,
288
+ [CoordinationType.META_COORDINATION_SCOPES]: newMetaCoordinationScopes,
289
+ [CoordinationType.META_COORDINATION_SCOPES_BY]: newMetaCoordinationScopesBy,
290
+ };
291
+ }