@jupytergis/base 0.13.2 → 0.14.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/lib/commands/BaseCommandIDs.d.ts +14 -13
- package/lib/commands/BaseCommandIDs.js +14 -14
- package/lib/commands/index.js +528 -130
- package/lib/commands/operationCommands.d.ts +22 -0
- package/lib/commands/operationCommands.js +305 -0
- package/lib/constants.js +11 -9
- package/lib/dialogs/ProcessingFormDialog.d.ts +1 -1
- package/lib/dialogs/ProcessingFormDialog.js +2 -2
- package/lib/dialogs/layerBrowserDialog.d.ts +2 -0
- package/lib/dialogs/layerBrowserDialog.js +12 -5
- package/lib/dialogs/layerCreationFormDialog.d.ts +7 -0
- package/lib/dialogs/layerCreationFormDialog.js +10 -2
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.d.ts +2 -1
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.js +21 -19
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.d.ts +3 -1
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.js +13 -5
- package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +6 -4
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +7 -11
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +7 -10
- package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +7 -8
- package/lib/formbuilder/creationform.d.ts +8 -8
- package/lib/formbuilder/creationform.js +130 -85
- package/lib/formbuilder/editform.d.ts +1 -7
- package/lib/formbuilder/editform.js +64 -52
- package/lib/formbuilder/formselectors.d.ts +5 -4
- package/lib/formbuilder/index.d.ts +1 -1
- package/lib/formbuilder/index.js +1 -1
- package/lib/formbuilder/objectform/SchemaForm.d.ts +36 -0
- package/lib/formbuilder/objectform/SchemaForm.js +77 -0
- package/lib/formbuilder/objectform/StoryEditorForm.d.ts +3 -9
- package/lib/formbuilder/objectform/StoryEditorForm.js +20 -14
- package/lib/formbuilder/objectform/components/LayerSelect.js +3 -8
- package/lib/formbuilder/objectform/components/SegmentFormSymbology.js +23 -10
- package/lib/formbuilder/objectform/components/SourcePropertiesField.d.ts +7 -0
- package/lib/formbuilder/objectform/components/SourcePropertiesField.js +29 -0
- package/lib/formbuilder/objectform/components/StorySegmentReset.js +1 -1
- package/lib/formbuilder/objectform/fileselectorwidget.js +1 -1
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.d.ts +3 -12
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.js +87 -55
- package/lib/formbuilder/objectform/layer/hillshadeLayerForm.d.ts +3 -8
- package/lib/formbuilder/objectform/layer/hillshadeLayerForm.js +36 -10
- package/lib/formbuilder/objectform/layer/layerform.d.ts +7 -9
- package/lib/formbuilder/objectform/layer/layerform.js +33 -20
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.d.ts +3 -5
- package/lib/formbuilder/objectform/layer/storySegmentLayerForm.js +73 -29
- package/lib/formbuilder/objectform/layer/vectorlayerform.d.ts +3 -14
- package/lib/formbuilder/objectform/layer/vectorlayerform.js +36 -29
- package/lib/formbuilder/objectform/layer/webGlLayerForm.d.ts +3 -10
- package/lib/formbuilder/objectform/layer/webGlLayerForm.js +37 -13
- package/lib/formbuilder/objectform/process/dissolveProcessForm.d.ts +8 -18
- package/lib/formbuilder/objectform/process/dissolveProcessForm.js +68 -56
- package/lib/formbuilder/objectform/processingForm.d.ts +12 -0
- package/lib/formbuilder/objectform/processingForm.js +33 -0
- package/lib/formbuilder/objectform/schemaUtils.d.ts +16 -0
- package/lib/formbuilder/objectform/schemaUtils.js +59 -0
- package/lib/formbuilder/objectform/source/geojsonsource.d.ts +3 -19
- package/lib/formbuilder/objectform/source/geojsonsource.js +94 -53
- package/lib/formbuilder/objectform/source/geotiffsource.d.ts +3 -20
- package/lib/formbuilder/objectform/source/geotiffsource.js +73 -74
- package/lib/formbuilder/objectform/source/pathbasedsource.d.ts +3 -19
- package/lib/formbuilder/objectform/source/pathbasedsource.js +76 -75
- package/lib/formbuilder/objectform/source/sourceform.d.ts +7 -8
- package/lib/formbuilder/objectform/source/sourceform.js +28 -11
- package/lib/formbuilder/objectform/source/tilesourceform.d.ts +3 -7
- package/lib/formbuilder/objectform/source/tilesourceform.js +63 -53
- package/lib/formbuilder/objectform/useSchemaFormState.d.ts +48 -0
- package/lib/formbuilder/objectform/useSchemaFormState.js +35 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/keybindings.json +10 -10
- package/lib/mainview/mainView.d.ts +11 -7
- package/lib/mainview/mainView.js +63 -36
- package/lib/mainview/mainviewmodel.js +2 -2
- package/lib/menus.js +8 -8
- package/lib/panelview/components/layers.js +5 -2
- package/lib/panelview/objectproperties.js +2 -2
- package/lib/panelview/rightpanel.js +17 -2
- package/lib/panelview/story-maps/SpectaPanel.d.ts +15 -0
- package/lib/panelview/story-maps/SpectaPanel.js +35 -0
- package/lib/panelview/story-maps/StoryViewerPanel.d.ts +24 -9
- package/lib/panelview/story-maps/StoryViewerPanel.js +22 -268
- package/lib/panelview/story-maps/{PreviewModeSwitch.js → components/PreviewModeSwitch.js} +1 -1
- package/lib/panelview/story-maps/components/SpectaDesktopView.d.ts +21 -0
- package/lib/panelview/story-maps/components/SpectaDesktopView.js +49 -0
- package/lib/panelview/story-maps/components/SpectaMobileView.d.ts +17 -0
- package/lib/panelview/story-maps/{MobileSpectaPanel.js → components/SpectaMobileView.js} +8 -22
- package/lib/panelview/story-maps/{StoryNavBar.d.ts → components/StoryNavBar.d.ts} +1 -1
- package/lib/panelview/story-maps/{StoryNavBar.js → components/StoryNavBar.js} +2 -4
- package/lib/panelview/story-maps/hooks/useStoryMap.d.ts +39 -0
- package/lib/panelview/story-maps/hooks/useStoryMap.js +252 -0
- package/lib/processing/index.d.ts +2 -2
- package/lib/processing/index.js +62 -35
- package/lib/processing/processingCommands.d.ts +1 -1
- package/lib/processing/processingCommands.js +26 -6
- package/lib/shared/components/Collapsible.d.ts +6 -0
- package/lib/shared/components/Collapsible.js +26 -0
- package/lib/statusbar/SpectaPresentationProgressBar.d.ts +7 -0
- package/lib/statusbar/SpectaPresentationProgressBar.js +40 -0
- package/lib/toolbar/widget.js +4 -2
- package/lib/tools.d.ts +6 -0
- package/lib/tools.js +9 -0
- package/lib/types.d.ts +29 -2
- package/lib/widget.js +14 -2
- package/package.json +2 -4
- package/style/base.css +23 -1
- package/style/dialog.css +5 -0
- package/style/leftPanel.css +14 -37
- package/style/shared/button.css +0 -10
- package/style/shared/switch.css +8 -7
- package/style/spectaProgressBar.css +144 -0
- package/style/storyPanel.css +33 -0
- package/style/symbologyDialog.css +2 -2
- package/lib/formbuilder/objectform/baseform.d.ts +0 -91
- package/lib/formbuilder/objectform/baseform.js +0 -231
- package/lib/panelview/story-maps/MobileSpectaPanel.d.ts +0 -7
- /package/lib/panelview/story-maps/{PreviewModeSwitch.d.ts → components/PreviewModeSwitch.d.ts} +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IRenderMime } from '@jupyterlab/rendermime';
|
|
2
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
3
|
+
import { JupyterGISTracker } from '../types';
|
|
4
|
+
export declare namespace LayerCreationCommandIDs {
|
|
5
|
+
const newGeoJSONWithParams = "jupytergis:newGeoJSONWithParams";
|
|
6
|
+
const newRasterWithParams = "jupytergis:newRasterWithParams";
|
|
7
|
+
const newVectorTileWithParams = "jupytergis:newVectorTileWithParams";
|
|
8
|
+
const newGeoParquetWithParams = "jupytergis:newGeoParquetWithParams";
|
|
9
|
+
const newHillshadeWithParams = "jupytergis:newHillshadeWithParams";
|
|
10
|
+
const newImageWithParams = "jupytergis:newImageWithParams";
|
|
11
|
+
const newVideoWithParams = "jupytergis:newVideoWithParams";
|
|
12
|
+
const newGeoTiffWithParams = "jupytergis:newGeoTiffWithParams";
|
|
13
|
+
const newShapefileWithParams = "jupytergis:newShapefileWithParams";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Register all layer creation commands using declarative specs.
|
|
17
|
+
*/
|
|
18
|
+
export declare function addLayerCreationCommands(options: {
|
|
19
|
+
tracker: JupyterGISTracker;
|
|
20
|
+
commands: CommandRegistry;
|
|
21
|
+
trans: IRenderMime.TranslationBundle;
|
|
22
|
+
}): void;
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { UUID } from '@lumino/coreutils';
|
|
2
|
+
export var LayerCreationCommandIDs;
|
|
3
|
+
(function (LayerCreationCommandIDs) {
|
|
4
|
+
LayerCreationCommandIDs.newGeoJSONWithParams = 'jupytergis:newGeoJSONWithParams';
|
|
5
|
+
LayerCreationCommandIDs.newRasterWithParams = 'jupytergis:newRasterWithParams';
|
|
6
|
+
LayerCreationCommandIDs.newVectorTileWithParams = 'jupytergis:newVectorTileWithParams';
|
|
7
|
+
LayerCreationCommandIDs.newGeoParquetWithParams = 'jupytergis:newGeoParquetWithParams';
|
|
8
|
+
LayerCreationCommandIDs.newHillshadeWithParams = 'jupytergis:newHillshadeWithParams';
|
|
9
|
+
LayerCreationCommandIDs.newImageWithParams = 'jupytergis:newImageWithParams';
|
|
10
|
+
LayerCreationCommandIDs.newVideoWithParams = 'jupytergis:newVideoWithParams';
|
|
11
|
+
LayerCreationCommandIDs.newGeoTiffWithParams = 'jupytergis:newGeoTiffWithParams';
|
|
12
|
+
LayerCreationCommandIDs.newShapefileWithParams = 'jupytergis:newShapefileWithParams';
|
|
13
|
+
})(LayerCreationCommandIDs || (LayerCreationCommandIDs = {}));
|
|
14
|
+
/**
|
|
15
|
+
* Generic command factory for layer creation.
|
|
16
|
+
*/
|
|
17
|
+
function createLayerCommand(commands, tracker, trans, spec) {
|
|
18
|
+
commands.addCommand(spec.id, {
|
|
19
|
+
label: trans.__(spec.label),
|
|
20
|
+
caption: trans.__(spec.caption),
|
|
21
|
+
isEnabled: () => true,
|
|
22
|
+
describedBy: {
|
|
23
|
+
args: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
required: ['filePath', 'name', 'parameters'],
|
|
26
|
+
properties: {
|
|
27
|
+
filePath: { type: 'string', description: 'Path to the .jGIS file' },
|
|
28
|
+
name: { type: 'string', description: 'Layer name' },
|
|
29
|
+
parameters: {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: Object.assign({ source: spec.sourceSchema }, spec.layerParamsSchema),
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
execute: (async (args) => {
|
|
37
|
+
const { filePath, name, parameters } = args;
|
|
38
|
+
const current = tracker.find(w => w.model.filePath === filePath);
|
|
39
|
+
if (!current || !current.model.sharedModel.editable) {
|
|
40
|
+
console.warn('Invalid or non-editable document for', filePath);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const model = current.model;
|
|
44
|
+
const sharedModel = model.sharedModel;
|
|
45
|
+
const sourceId = UUID.uuid4();
|
|
46
|
+
const layerId = UUID.uuid4();
|
|
47
|
+
const sourceModel = {
|
|
48
|
+
type: spec.sourceType,
|
|
49
|
+
name: `${name} Source`,
|
|
50
|
+
parameters: parameters.source,
|
|
51
|
+
};
|
|
52
|
+
sharedModel.addSource(sourceId, sourceModel);
|
|
53
|
+
const layerModel = {
|
|
54
|
+
type: spec.layerType,
|
|
55
|
+
name: name,
|
|
56
|
+
visible: true,
|
|
57
|
+
parameters: spec.buildParameters(parameters, sourceId),
|
|
58
|
+
};
|
|
59
|
+
model.addLayer(layerId, layerModel);
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Register all layer creation commands using declarative specs.
|
|
65
|
+
*/
|
|
66
|
+
export function addLayerCreationCommands(options) {
|
|
67
|
+
const { tracker, commands, trans } = options;
|
|
68
|
+
const specs = [
|
|
69
|
+
{
|
|
70
|
+
id: LayerCreationCommandIDs.newGeoJSONWithParams,
|
|
71
|
+
label: 'New GeoJSON Layer From Parameters',
|
|
72
|
+
caption: 'Add a new GeoJSON vector layer (by file path or URL) and add it to the given JupyterGIS file',
|
|
73
|
+
sourceType: 'GeoJSONSource',
|
|
74
|
+
layerType: 'VectorLayer',
|
|
75
|
+
sourceSchema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
required: ['path'],
|
|
78
|
+
properties: { path: { type: 'string' } },
|
|
79
|
+
},
|
|
80
|
+
layerParamsSchema: {
|
|
81
|
+
color: { type: 'object' },
|
|
82
|
+
opacity: { type: 'number', default: 1 },
|
|
83
|
+
symbologyState: { type: 'object' },
|
|
84
|
+
},
|
|
85
|
+
buildParameters: (p, id) => {
|
|
86
|
+
var _a, _b;
|
|
87
|
+
return ({
|
|
88
|
+
source: id,
|
|
89
|
+
color: (_a = p.color) !== null && _a !== void 0 ? _a : {},
|
|
90
|
+
opacity: (_b = p.opacity) !== null && _b !== void 0 ? _b : 1,
|
|
91
|
+
symbologyState: p.symbologyState,
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: LayerCreationCommandIDs.newRasterWithParams,
|
|
97
|
+
label: 'New Raster Layer From Parameters',
|
|
98
|
+
caption: 'Add a new raster layer (by file path or URL) and add it to the given JupyterGIS file',
|
|
99
|
+
sourceType: 'RasterSource',
|
|
100
|
+
layerType: 'RasterLayer',
|
|
101
|
+
sourceSchema: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
required: ['url'],
|
|
104
|
+
properties: { url: { type: 'string' } },
|
|
105
|
+
},
|
|
106
|
+
layerParamsSchema: { opacity: { type: 'number', default: 1 } },
|
|
107
|
+
buildParameters: (p, id) => {
|
|
108
|
+
var _a;
|
|
109
|
+
return ({
|
|
110
|
+
source: id,
|
|
111
|
+
opacity: (_a = p.opacity) !== null && _a !== void 0 ? _a : 1,
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: LayerCreationCommandIDs.newVectorTileWithParams,
|
|
117
|
+
label: 'New Vector Tile Layer From Parameters',
|
|
118
|
+
caption: 'Add a new vector tile layer (by URL) and add it to the given JupyterGIS file',
|
|
119
|
+
sourceType: 'VectorTileSource',
|
|
120
|
+
layerType: 'VectorTileLayer',
|
|
121
|
+
sourceSchema: {
|
|
122
|
+
type: 'object',
|
|
123
|
+
required: ['url'],
|
|
124
|
+
properties: { url: { type: 'string' } },
|
|
125
|
+
},
|
|
126
|
+
layerParamsSchema: {
|
|
127
|
+
color: { type: 'object' },
|
|
128
|
+
opacity: { type: 'number', default: 1 },
|
|
129
|
+
},
|
|
130
|
+
buildParameters: (p, id) => {
|
|
131
|
+
var _a, _b;
|
|
132
|
+
return ({
|
|
133
|
+
source: id,
|
|
134
|
+
color: (_a = p.color) !== null && _a !== void 0 ? _a : {},
|
|
135
|
+
opacity: (_b = p.opacity) !== null && _b !== void 0 ? _b : 1,
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: LayerCreationCommandIDs.newGeoParquetWithParams,
|
|
141
|
+
label: 'New GeoParquet Layer From Parameters',
|
|
142
|
+
caption: 'Add a new GeoParquet vector layer (by file path or URL) and add it to the given JupyterGIS file',
|
|
143
|
+
sourceType: 'GeoParquetSource',
|
|
144
|
+
layerType: 'VectorLayer',
|
|
145
|
+
sourceSchema: {
|
|
146
|
+
type: 'object',
|
|
147
|
+
required: ['path'],
|
|
148
|
+
properties: { path: { type: 'string' } },
|
|
149
|
+
},
|
|
150
|
+
layerParamsSchema: {
|
|
151
|
+
color: { type: 'object' },
|
|
152
|
+
opacity: { type: 'number', default: 1 },
|
|
153
|
+
symbologyState: { type: 'object' },
|
|
154
|
+
},
|
|
155
|
+
buildParameters: (p, id) => {
|
|
156
|
+
var _a, _b;
|
|
157
|
+
return ({
|
|
158
|
+
source: id,
|
|
159
|
+
color: (_a = p.color) !== null && _a !== void 0 ? _a : {},
|
|
160
|
+
opacity: (_b = p.opacity) !== null && _b !== void 0 ? _b : 1,
|
|
161
|
+
symbologyState: p.symbologyState,
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: LayerCreationCommandIDs.newHillshadeWithParams,
|
|
167
|
+
label: 'New Hillshade Layer From Parameters',
|
|
168
|
+
caption: 'Add a new hillshade layer (by DEM raster source) and add it to the given JupyterGIS file',
|
|
169
|
+
sourceType: 'RasterDemSource',
|
|
170
|
+
layerType: 'HillshadeLayer',
|
|
171
|
+
sourceSchema: {
|
|
172
|
+
type: 'object',
|
|
173
|
+
required: ['url'],
|
|
174
|
+
properties: { url: { type: 'string' } },
|
|
175
|
+
},
|
|
176
|
+
layerParamsSchema: {
|
|
177
|
+
shadowColor: { type: 'string', default: '#473B24' },
|
|
178
|
+
},
|
|
179
|
+
buildParameters: (p, id) => {
|
|
180
|
+
var _a;
|
|
181
|
+
return ({
|
|
182
|
+
source: id,
|
|
183
|
+
shadowColor: (_a = p.shadowColor) !== null && _a !== void 0 ? _a : '#473B24',
|
|
184
|
+
});
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: LayerCreationCommandIDs.newImageWithParams,
|
|
189
|
+
label: 'New Image Layer From Parameters',
|
|
190
|
+
caption: 'Add a new image layer (by file path or URL) and add it to the given JupyterGIS file',
|
|
191
|
+
sourceType: 'ImageSource',
|
|
192
|
+
layerType: 'ImageLayer',
|
|
193
|
+
sourceSchema: {
|
|
194
|
+
type: 'object',
|
|
195
|
+
required: ['path', 'coordinates'],
|
|
196
|
+
properties: {
|
|
197
|
+
path: { type: 'string' },
|
|
198
|
+
coordinates: {
|
|
199
|
+
type: 'array',
|
|
200
|
+
items: { type: 'array', items: { type: 'number' } },
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
layerParamsSchema: { opacity: { type: 'number', default: 1 } },
|
|
205
|
+
buildParameters: (p, id) => {
|
|
206
|
+
var _a;
|
|
207
|
+
return ({
|
|
208
|
+
source: id,
|
|
209
|
+
opacity: (_a = p.opacity) !== null && _a !== void 0 ? _a : 1,
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
id: LayerCreationCommandIDs.newVideoWithParams,
|
|
215
|
+
label: 'New Video Layer From Parameters',
|
|
216
|
+
caption: 'Add a new video layer (by file path or URL) and add it to the given JupyterGIS file',
|
|
217
|
+
sourceType: 'VideoSource',
|
|
218
|
+
layerType: 'RasterLayer',
|
|
219
|
+
sourceSchema: {
|
|
220
|
+
type: 'object',
|
|
221
|
+
required: ['urls', 'coordinates'],
|
|
222
|
+
properties: {
|
|
223
|
+
urls: { type: 'array', items: { type: 'string' } },
|
|
224
|
+
coordinates: {
|
|
225
|
+
type: 'array',
|
|
226
|
+
items: { type: 'array', items: { type: 'number' } },
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
layerParamsSchema: { opacity: { type: 'number', default: 1 } },
|
|
231
|
+
buildParameters: (p, id) => {
|
|
232
|
+
var _a;
|
|
233
|
+
return ({
|
|
234
|
+
source: id,
|
|
235
|
+
opacity: (_a = p.opacity) !== null && _a !== void 0 ? _a : 1,
|
|
236
|
+
});
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: LayerCreationCommandIDs.newGeoTiffWithParams,
|
|
241
|
+
label: 'New GeoTIFF Layer From Parameters',
|
|
242
|
+
caption: 'Add a new GeoTIFF layer (by file path or URL) and add it to the given JupyterGIS file',
|
|
243
|
+
sourceType: 'GeoTiffSource',
|
|
244
|
+
layerType: 'WebGlLayer',
|
|
245
|
+
sourceSchema: {
|
|
246
|
+
type: 'object',
|
|
247
|
+
required: ['urls'],
|
|
248
|
+
properties: {
|
|
249
|
+
urls: {
|
|
250
|
+
type: 'array',
|
|
251
|
+
items: {
|
|
252
|
+
type: 'object',
|
|
253
|
+
properties: {
|
|
254
|
+
url: { type: 'string' },
|
|
255
|
+
min: { type: 'number' },
|
|
256
|
+
max: { type: 'number' },
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
layerParamsSchema: {
|
|
263
|
+
opacity: { type: 'number', default: 1 },
|
|
264
|
+
color: { type: 'any' },
|
|
265
|
+
symbologyState: { type: 'object' },
|
|
266
|
+
},
|
|
267
|
+
buildParameters: (p, id) => {
|
|
268
|
+
var _a, _b;
|
|
269
|
+
return ({
|
|
270
|
+
source: id,
|
|
271
|
+
opacity: (_a = p.opacity) !== null && _a !== void 0 ? _a : 1,
|
|
272
|
+
color: p.color,
|
|
273
|
+
symbologyState: (_b = p.symbologyState) !== null && _b !== void 0 ? _b : { renderType: 'continuous' },
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: LayerCreationCommandIDs.newShapefileWithParams,
|
|
279
|
+
label: 'New Shapefile Layer From Parameters',
|
|
280
|
+
caption: 'Add a new Shapefile vector layer (by file path or URL) and add it to the given JupyterGIS file',
|
|
281
|
+
sourceType: 'ShapefileSource',
|
|
282
|
+
layerType: 'VectorLayer',
|
|
283
|
+
sourceSchema: {
|
|
284
|
+
type: 'object',
|
|
285
|
+
required: ['path'],
|
|
286
|
+
properties: { path: { type: 'string' } },
|
|
287
|
+
},
|
|
288
|
+
layerParamsSchema: {
|
|
289
|
+
color: { type: 'object' },
|
|
290
|
+
opacity: { type: 'number', default: 1 },
|
|
291
|
+
symbologyState: { type: 'object' },
|
|
292
|
+
},
|
|
293
|
+
buildParameters: (p, id) => {
|
|
294
|
+
var _a, _b, _c;
|
|
295
|
+
return ({
|
|
296
|
+
source: id,
|
|
297
|
+
color: (_a = p.color) !== null && _a !== void 0 ? _a : {},
|
|
298
|
+
opacity: (_b = p.opacity) !== null && _b !== void 0 ? _b : 1,
|
|
299
|
+
symbologyState: (_c = p.symbologyState) !== null && _c !== void 0 ? _c : { renderType: 'Single Symbol' },
|
|
300
|
+
});
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
];
|
|
304
|
+
specs.forEach(spec => createLayerCommand(commands, tracker, trans, spec));
|
|
305
|
+
}
|
package/lib/constants.js
CHANGED
|
@@ -22,15 +22,15 @@ const iconObject = {
|
|
|
22
22
|
[CommandIDs.redo]: { icon: redoIcon },
|
|
23
23
|
[CommandIDs.undo]: { icon: undoIcon },
|
|
24
24
|
[CommandIDs.openLayerBrowser]: { icon: bookOpenIcon },
|
|
25
|
-
[CommandIDs.
|
|
26
|
-
[CommandIDs.
|
|
27
|
-
[CommandIDs.
|
|
28
|
-
[CommandIDs.
|
|
29
|
-
[CommandIDs.
|
|
30
|
-
[CommandIDs.
|
|
31
|
-
[CommandIDs.
|
|
32
|
-
[CommandIDs.
|
|
33
|
-
[CommandIDs.
|
|
25
|
+
[CommandIDs.openNewRasterDialog]: { icon: rasterIcon },
|
|
26
|
+
[CommandIDs.openNewVectorTileDialog]: { icon: vectorSquareIcon },
|
|
27
|
+
[CommandIDs.openNewGeoJSONDialog]: { icon: geoJSONIcon },
|
|
28
|
+
[CommandIDs.openNewHillshadeDialog]: { icon: moundIcon },
|
|
29
|
+
[CommandIDs.openNewImageDialog]: { iconClass: 'fa fa-image' },
|
|
30
|
+
[CommandIDs.openNewVideoDialog]: { iconClass: 'fa fa-video' },
|
|
31
|
+
[CommandIDs.openNewShapefileDialog]: { iconClass: 'fa fa-file' },
|
|
32
|
+
[CommandIDs.openNewGeoTiffDialog]: { iconClass: 'fa fa-image' },
|
|
33
|
+
[CommandIDs.openNewGeoParquetDialog]: { iconClass: 'fa fa-file' },
|
|
34
34
|
[CommandIDs.symbology]: { iconClass: 'fa fa-brush' },
|
|
35
35
|
[CommandIDs.identify]: { icon: infoIcon },
|
|
36
36
|
[CommandIDs.temporalController]: { icon: clockIcon },
|
|
@@ -39,6 +39,8 @@ const iconObject = {
|
|
|
39
39
|
[CommandIDs.toggleStoryPresentationMode]: {
|
|
40
40
|
iconClass: 'fa fa-book jgis-icon-adjust',
|
|
41
41
|
},
|
|
42
|
+
[CommandIDs.renameSelected]: { iconClass: 'fa fa-pen' },
|
|
43
|
+
[CommandIDs.removeSelected]: { iconClass: 'fa fa-trash' },
|
|
42
44
|
};
|
|
43
45
|
/**
|
|
44
46
|
* The registered icons
|
|
@@ -2,7 +2,7 @@ import { ProcessingType, IDict, IJupyterGISModel } from '@jupytergis/schema';
|
|
|
2
2
|
import { Dialog } from '@jupyterlab/apputils';
|
|
3
3
|
import { PromiseDelegate } from '@lumino/coreutils';
|
|
4
4
|
import { Signal } from '@lumino/signaling';
|
|
5
|
-
import { IBaseFormProps } from "../
|
|
5
|
+
import type { IBaseFormProps } from "../types";
|
|
6
6
|
export interface IProcessingFormDialogOptions extends IBaseFormProps {
|
|
7
7
|
formContext: 'update' | 'create';
|
|
8
8
|
schema: IDict;
|
|
@@ -2,8 +2,8 @@ import { Dialog } from '@jupyterlab/apputils';
|
|
|
2
2
|
import { PromiseDelegate } from '@lumino/coreutils';
|
|
3
3
|
import { Signal } from '@lumino/signaling';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import { BaseForm, } from "../formbuilder/objectform/baseform";
|
|
6
5
|
import { DissolveForm } from "../formbuilder/objectform/process";
|
|
6
|
+
import { DefaultProcessingForm } from "../formbuilder/objectform/processingForm";
|
|
7
7
|
const ProcessingFormWrapper = props => {
|
|
8
8
|
var _a;
|
|
9
9
|
const [ready, setReady] = React.useState(false);
|
|
@@ -23,7 +23,7 @@ const ProcessingFormWrapper = props => {
|
|
|
23
23
|
FormComponent = DissolveForm;
|
|
24
24
|
break;
|
|
25
25
|
default:
|
|
26
|
-
FormComponent =
|
|
26
|
+
FormComponent = DefaultProcessingForm;
|
|
27
27
|
}
|
|
28
28
|
return (ready && (React.createElement(FormComponent, { formContext: props.formContext, filePath: props.model.filePath, model: props.model, ok: okSignal.current, sourceData: props.sourceData, schema: props.schema, syncData: props.syncData })));
|
|
29
29
|
};
|
|
@@ -9,6 +9,7 @@ interface ILayerBrowserDialogProps {
|
|
|
9
9
|
formSchemaRegistry: IJGISFormSchemaRegistry;
|
|
10
10
|
okSignalPromise: PromiseDelegate<Signal<Dialog<any>, number>>;
|
|
11
11
|
cancel: () => void;
|
|
12
|
+
registerConfirmHandler?: (fn: () => void) => void;
|
|
12
13
|
}
|
|
13
14
|
export declare const LayerBrowserComponent: React.FC<ILayerBrowserDialogProps>;
|
|
14
15
|
export interface ILayerBrowserOptions {
|
|
@@ -19,6 +20,7 @@ export interface ILayerBrowserOptions {
|
|
|
19
20
|
export declare class LayerBrowserWidget extends Dialog<boolean> {
|
|
20
21
|
constructor(options: ILayerBrowserOptions);
|
|
21
22
|
resolve(index?: number): void;
|
|
23
|
+
private _getConfirmHandler;
|
|
22
24
|
private okSignal;
|
|
23
25
|
}
|
|
24
26
|
export {};
|
|
@@ -6,7 +6,7 @@ import { Signal } from '@lumino/signaling';
|
|
|
6
6
|
import React, { useEffect, useState } from 'react';
|
|
7
7
|
import { CreationFormWrapper } from './layerCreationFormDialog';
|
|
8
8
|
import CUSTOM_RASTER_IMAGE from '../../layer_gallery/custom_raster.png';
|
|
9
|
-
export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okSignalPromise, cancel, }) => {
|
|
9
|
+
export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okSignalPromise, cancel, registerConfirmHandler, }) => {
|
|
10
10
|
const [searchTerm, setSearchTerm] = useState('');
|
|
11
11
|
const [activeLayers, setActiveLayers] = useState([]);
|
|
12
12
|
const [selectedCategory, setSelectedCategory] = useState();
|
|
@@ -78,7 +78,7 @@ export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okS
|
|
|
78
78
|
maxZoom: 24,
|
|
79
79
|
minZoom: 0,
|
|
80
80
|
attribution: '(C) OpenStreetMap contributors',
|
|
81
|
-
}, okSignalPromise: okSignalPromise, cancel: cancel })));
|
|
81
|
+
}, okSignalPromise: okSignalPromise, cancel: cancel, registerConfirmHandler: registerConfirmHandler })));
|
|
82
82
|
}
|
|
83
83
|
// Ok is like cancel in the case of gallery item selections
|
|
84
84
|
okSignalPromise.promise.then(value => {
|
|
@@ -116,25 +116,32 @@ export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okS
|
|
|
116
116
|
};
|
|
117
117
|
export class LayerBrowserWidget extends Dialog {
|
|
118
118
|
constructor(options) {
|
|
119
|
-
|
|
120
|
-
cancelCallback = () => {
|
|
119
|
+
const cancelCallback = () => {
|
|
121
120
|
this.resolve(0);
|
|
122
121
|
};
|
|
122
|
+
let confirmHandler = null;
|
|
123
|
+
const registerConfirmHandler = (fn) => {
|
|
124
|
+
confirmHandler = fn;
|
|
125
|
+
};
|
|
123
126
|
const okSignalPromise = new PromiseDelegate();
|
|
124
|
-
const body = (React.createElement(LayerBrowserComponent, { model: options.model, registry: options.registry, formSchemaRegistry: options.formSchemaRegistry, okSignalPromise: okSignalPromise, cancel: cancelCallback }));
|
|
127
|
+
const body = (React.createElement(LayerBrowserComponent, { model: options.model, registry: options.registry, formSchemaRegistry: options.formSchemaRegistry, okSignalPromise: okSignalPromise, cancel: cancelCallback, registerConfirmHandler: registerConfirmHandler }));
|
|
125
128
|
super({ body, buttons: [Dialog.cancelButton(), Dialog.okButton()] });
|
|
126
129
|
this.id = 'jupytergis::layerBrowser';
|
|
130
|
+
this._getConfirmHandler = () => confirmHandler;
|
|
127
131
|
this.okSignal = new Signal(this);
|
|
128
132
|
okSignalPromise.resolve(this.okSignal);
|
|
129
133
|
// Override default dialog style
|
|
130
134
|
this.addClass('jGIS-layerbrowser-FormDialog');
|
|
131
135
|
}
|
|
132
136
|
resolve(index) {
|
|
137
|
+
var _a;
|
|
133
138
|
if (index === 0) {
|
|
134
139
|
super.resolve(index);
|
|
135
140
|
}
|
|
136
141
|
if (index === 1) {
|
|
142
|
+
(_a = this._getConfirmHandler()) === null || _a === void 0 ? void 0 : _a();
|
|
137
143
|
this.okSignal.emit(1);
|
|
144
|
+
super.resolve(index);
|
|
138
145
|
}
|
|
139
146
|
}
|
|
140
147
|
}
|
|
@@ -21,6 +21,12 @@ export interface ICreationFormWrapperProps extends ICreationFormProps {
|
|
|
21
21
|
* and other form-related parameters.
|
|
22
22
|
*/
|
|
23
23
|
dialogOptions?: any;
|
|
24
|
+
/**
|
|
25
|
+
* Optional. When provided, the form body can register a handler that the dialog
|
|
26
|
+
* will invoke when the user clicks OK. If no handler is
|
|
27
|
+
* registered, only the ok signal is emitted.
|
|
28
|
+
*/
|
|
29
|
+
registerConfirmHandler?: (fn: () => void) => void;
|
|
24
30
|
}
|
|
25
31
|
export interface ICreationFormDialogOptions extends ICreationFormProps {
|
|
26
32
|
title: string;
|
|
@@ -32,5 +38,6 @@ export declare const CreationFormWrapper: React.FC<ICreationFormWrapperProps>;
|
|
|
32
38
|
export declare class LayerCreationFormDialog extends Dialog<IDict> {
|
|
33
39
|
constructor(options: ICreationFormDialogOptions);
|
|
34
40
|
resolve(index?: number): void;
|
|
41
|
+
private _getConfirmHandler;
|
|
35
42
|
private okSignal;
|
|
36
43
|
}
|
|
@@ -16,7 +16,7 @@ export const CreationFormWrapper = props => {
|
|
|
16
16
|
formErrorSignal.current = formChanged;
|
|
17
17
|
setReady(true);
|
|
18
18
|
});
|
|
19
|
-
return (ready && (React.createElement(CreationForm, { model: props.model, formSchemaRegistry: props.formSchemaRegistry, createLayer: props.createLayer, createSource: props.createSource, layerType: props.layerType, sourceType: props.sourceType, sourceData: props.sourceData, layerData: props.layerData,
|
|
19
|
+
return (ready && (React.createElement(CreationForm, { model: props.model, formSchemaRegistry: props.formSchemaRegistry, createLayer: props.createLayer, createSource: props.createSource, layerType: props.layerType, sourceType: props.sourceType, sourceData: props.sourceData, layerData: props.layerData, cancel: props.cancel, formErrorSignal: formErrorSignal.current, dialogOptions: props.dialogOptions, registerConfirmHandler: props.registerConfirmHandler })));
|
|
20
20
|
};
|
|
21
21
|
/**
|
|
22
22
|
* Form for creating a source, a layer or both at the same time
|
|
@@ -26,15 +26,20 @@ export class LayerCreationFormDialog extends Dialog {
|
|
|
26
26
|
const cancelCallback = () => {
|
|
27
27
|
this.resolve(0);
|
|
28
28
|
};
|
|
29
|
+
let confirmHandler = null;
|
|
30
|
+
const registerConfirmHandler = (fn) => {
|
|
31
|
+
confirmHandler = fn;
|
|
32
|
+
};
|
|
29
33
|
const okSignalPromise = new PromiseDelegate();
|
|
30
34
|
const formErrorSignalPromise = new PromiseDelegate();
|
|
31
35
|
const body = (React.createElement("div", { style: { overflow: 'auto' } },
|
|
32
|
-
React.createElement(CreationFormWrapper, { model: options.model, formSchemaRegistry: options.formSchemaRegistry, createLayer: options.createLayer, createSource: options.createSource, layerType: options.layerType, sourceType: options.sourceType, sourceData: options.sourceData, layerData: options.layerData, okSignalPromise: okSignalPromise, cancel: cancelCallback, formErrorSignalPromise: formErrorSignalPromise, dialogOptions: options })));
|
|
36
|
+
React.createElement(CreationFormWrapper, { model: options.model, formSchemaRegistry: options.formSchemaRegistry, createLayer: options.createLayer, createSource: options.createSource, layerType: options.layerType, sourceType: options.sourceType, sourceData: options.sourceData, layerData: options.layerData, okSignalPromise: okSignalPromise, cancel: cancelCallback, formErrorSignalPromise: formErrorSignalPromise, dialogOptions: options, registerConfirmHandler: registerConfirmHandler })));
|
|
33
37
|
super({
|
|
34
38
|
title: options.title,
|
|
35
39
|
body,
|
|
36
40
|
buttons: [Dialog.cancelButton(), Dialog.okButton()],
|
|
37
41
|
});
|
|
42
|
+
this._getConfirmHandler = () => confirmHandler;
|
|
38
43
|
this.okSignal = new Signal(this);
|
|
39
44
|
const formErrorSignal = new Signal(this);
|
|
40
45
|
/**
|
|
@@ -58,11 +63,14 @@ export class LayerCreationFormDialog extends Dialog {
|
|
|
58
63
|
this.addClass('jGIS-layer-CreationFormDialog');
|
|
59
64
|
}
|
|
60
65
|
resolve(index) {
|
|
66
|
+
var _a;
|
|
61
67
|
if (index === 0) {
|
|
62
68
|
super.resolve(index);
|
|
63
69
|
}
|
|
64
70
|
if (index === 1) {
|
|
71
|
+
(_a = this._getConfirmHandler()) === null || _a === void 0 ? void 0 : _a();
|
|
65
72
|
this.okSignal.emit(1);
|
|
73
|
+
super.resolve(index);
|
|
66
74
|
}
|
|
67
75
|
}
|
|
68
76
|
}
|
|
@@ -23,7 +23,7 @@ import { ColorRampName } from '../../colorRampUtils';
|
|
|
23
23
|
interface IColorRampControlsProps {
|
|
24
24
|
modeOptions: ClassificationMode[];
|
|
25
25
|
layerParams: IDict;
|
|
26
|
-
classifyFunc: (selectedMode: ClassificationMode, numberOfShades: number, selectedRamp: ColorRampName, setIsLoading: (isLoading: boolean) => void) => void;
|
|
26
|
+
classifyFunc: (selectedMode: ClassificationMode, numberOfShades: number, selectedRamp: ColorRampName, reverseRamp: boolean, setIsLoading: (isLoading: boolean) => void) => void;
|
|
27
27
|
showModeRow: boolean;
|
|
28
28
|
showRampSelector: boolean;
|
|
29
29
|
}
|
|
@@ -31,6 +31,7 @@ export type ColorRampControlsOptions = {
|
|
|
31
31
|
selectedRamp: ColorRampName;
|
|
32
32
|
numberOfShades: number;
|
|
33
33
|
selectedMode: ClassificationMode;
|
|
34
|
+
reverseRamp: boolean;
|
|
34
35
|
};
|
|
35
36
|
declare const ColorRampControls: React.FC<IColorRampControlsProps>;
|
|
36
37
|
export default ColorRampControls;
|
|
@@ -28,25 +28,19 @@ const ColorRampControls = ({ layerParams, modeOptions, classifyFunc, showModeRow
|
|
|
28
28
|
const [selectedMode, setSelectedMode] = useState('equal interval');
|
|
29
29
|
const [numberOfShades, setNumberOfShades] = useState(9);
|
|
30
30
|
const [isLoading, setIsLoading] = useState(false);
|
|
31
|
+
const [reverseRamp, setReverseRamp] = useState(false);
|
|
31
32
|
const [warning, setWarning] = useState(null);
|
|
33
|
+
const symbologyState = layerParams.symbologyState;
|
|
32
34
|
useEffect(() => {
|
|
33
|
-
if (
|
|
35
|
+
if (symbologyState) {
|
|
34
36
|
populateOptions();
|
|
35
37
|
}
|
|
36
38
|
}, [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
symbologyState.colorRamp,
|
|
40
|
+
symbologyState.nClasses,
|
|
41
|
+
symbologyState.mode,
|
|
42
|
+
symbologyState.reverseRamp,
|
|
40
43
|
]);
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
var _a;
|
|
43
|
-
if (!selectedRamp) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const defaultClasses = (_a = COLOR_RAMP_DEFAULTS[selectedRamp]) !== null && _a !== void 0 ? _a : 9;
|
|
47
|
-
setNumberOfShades(defaultClasses);
|
|
48
|
-
setWarning(null);
|
|
49
|
-
}, [selectedRamp]);
|
|
50
44
|
useEffect(() => {
|
|
51
45
|
if (!selectedRamp || !numberOfShades) {
|
|
52
46
|
return;
|
|
@@ -65,18 +59,26 @@ const ColorRampControls = ({ layerParams, modeOptions, classifyFunc, showModeRow
|
|
|
65
59
|
}
|
|
66
60
|
}, [selectedRamp, numberOfShades]);
|
|
67
61
|
const populateOptions = () => {
|
|
68
|
-
var _a, _b
|
|
69
|
-
const { nClasses, mode, colorRamp } =
|
|
62
|
+
var _a, _b;
|
|
63
|
+
const { nClasses, mode, colorRamp, reverseRamp } = symbologyState !== null && symbologyState !== void 0 ? symbologyState : {};
|
|
70
64
|
setNumberOfShades(Number(nClasses !== null && nClasses !== void 0 ? nClasses : 9));
|
|
71
|
-
setSelectedMode((
|
|
72
|
-
setSelectedRamp((
|
|
65
|
+
setSelectedMode((_a = mode) !== null && _a !== void 0 ? _a : 'equal interval');
|
|
66
|
+
setSelectedRamp((_b = colorRamp) !== null && _b !== void 0 ? _b : 'viridis');
|
|
67
|
+
setReverseRamp(Boolean(reverseRamp !== null && reverseRamp !== void 0 ? reverseRamp : false));
|
|
68
|
+
};
|
|
69
|
+
const handleRampChange = (selectedRamp) => {
|
|
70
|
+
var _a;
|
|
71
|
+
setSelectedRamp(selectedRamp);
|
|
72
|
+
const defaultClasses = (_a = COLOR_RAMP_DEFAULTS[selectedRamp]) !== null && _a !== void 0 ? _a : 9;
|
|
73
|
+
setNumberOfShades(defaultClasses);
|
|
74
|
+
setWarning(null);
|
|
73
75
|
};
|
|
74
76
|
return (React.createElement("div", { className: "jp-gis-color-ramp-container" },
|
|
75
77
|
showRampSelector && (React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
76
78
|
React.createElement("label", { htmlFor: "color-ramp-select" }, "Color Ramp:"),
|
|
77
|
-
React.createElement(ColorRampSelector, { selectedRamp: selectedRamp, setSelected:
|
|
79
|
+
React.createElement(ColorRampSelector, { selectedRamp: selectedRamp, setSelected: handleRampChange, reverse: reverseRamp, setReverse: setReverseRamp }))),
|
|
78
80
|
showModeRow && (React.createElement(ModeSelectRow, { modeOptions: modeOptions, numberOfShades: numberOfShades, setNumberOfShades: setNumberOfShades, selectedMode: selectedMode, setSelectedMode: setSelectedMode })),
|
|
79
81
|
warning && (React.createElement("div", { className: "jp-gis-warning", style: { color: 'orange', marginTop: 4 } }, warning)),
|
|
80
|
-
isLoading ? (React.createElement(LoadingIcon, null)) : (React.createElement(Button, { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", disabled: !isValidNumberOfShades(numberOfShades) || !selectedMode || !!warning, onClick: () => classifyFunc(selectedMode, numberOfShades, selectedRamp, setIsLoading) }, "Classify"))));
|
|
82
|
+
isLoading ? (React.createElement(LoadingIcon, null)) : (React.createElement(Button, { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", disabled: !isValidNumberOfShades(numberOfShades) || !selectedMode || !!warning, onClick: () => classifyFunc(selectedMode, numberOfShades, selectedRamp, reverseRamp, setIsLoading) }, "Classify"))));
|
|
81
83
|
};
|
|
82
84
|
export default ColorRampControls;
|
|
@@ -14,7 +14,9 @@ import React from 'react';
|
|
|
14
14
|
import { ColorRampName } from "../../colorRampUtils";
|
|
15
15
|
interface IColorRampSelectorProps {
|
|
16
16
|
selectedRamp: ColorRampName;
|
|
17
|
-
setSelected: (
|
|
17
|
+
setSelected: (value: ColorRampName) => void;
|
|
18
|
+
reverse: boolean;
|
|
19
|
+
setReverse: React.Dispatch<React.SetStateAction<boolean>>;
|
|
18
20
|
}
|
|
19
21
|
declare const ColorRampSelector: React.FC<IColorRampSelectorProps>;
|
|
20
22
|
export default ColorRampSelector;
|