@cdc/map 4.25.3 → 4.25.6

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 (119) hide show
  1. package/.idea/map.iml +12 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/dist/cdcmap.js +31254 -32242
  5. package/examples/hex-colors.json +3 -3
  6. package/examples/m2.json +32904 -0
  7. package/examples/private/test.json +470 -1457
  8. package/examples/private/{mmr.json → wastewatermap.json} +86 -115
  9. package/index.html +36 -63
  10. package/package.json +7 -19
  11. package/src/CdcMap.tsx +56 -1552
  12. package/src/CdcMapComponent.tsx +608 -0
  13. package/src/_stories/CdcMap.Legend.Gradient.stories.tsx +10 -0
  14. package/src/_stories/CdcMap.Legend.stories.tsx +67 -0
  15. package/src/_stories/CdcMap.Table.stories.tsx +19 -0
  16. package/src/_stories/CdcMap.stories.tsx +12 -1
  17. package/src/_stories/UsaMap.NoData.stories.tsx +4 -4
  18. package/src/_stories/_mock/default-patterns.json +8 -5
  19. package/src/_stories/_mock/legend-bins.json +428 -0
  20. package/{examples/private/default-patterns.json → src/_stories/_mock/legends/legend-tests.json} +36 -131
  21. package/src/cdcMapComponent.styles.css +9 -0
  22. package/src/components/Annotation/Annotation.Draggable.tsx +27 -26
  23. package/src/components/Annotation/AnnotationDropdown.tsx +5 -6
  24. package/src/components/BubbleList.tsx +135 -49
  25. package/src/components/CityList.tsx +89 -87
  26. package/src/components/DataTable.tsx +8 -8
  27. package/src/components/EditorPanel/components/EditorPanel.tsx +823 -885
  28. package/src/components/EditorPanel/components/Error.tsx +9 -2
  29. package/src/components/EditorPanel/components/HexShapeSettings.tsx +127 -141
  30. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +55 -86
  31. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +89 -75
  32. package/src/components/EditorPanel/components/editorPanel.styles.css +95 -0
  33. package/src/components/Geo.tsx +9 -1
  34. package/src/components/GoogleMap/components/GoogleMap.tsx +1 -1
  35. package/src/components/Legend/components/Legend.tsx +92 -87
  36. package/src/components/Legend/components/LegendGroup/Legend.Group.tsx +128 -0
  37. package/src/components/Legend/components/LegendGroup/legend.group.css +27 -0
  38. package/src/components/Legend/components/LegendItem.Hex.tsx +4 -1
  39. package/src/components/Legend/components/index.scss +74 -17
  40. package/src/components/Modal.tsx +17 -7
  41. package/src/components/NavigationMenu.tsx +11 -9
  42. package/src/components/UsaMap/components/SingleState/SingleState.CountyOutput.tsx +12 -8
  43. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +4 -4
  44. package/src/components/UsaMap/components/TerritoriesSection.tsx +33 -10
  45. package/src/components/UsaMap/components/Territory/Territory.Hexagon.tsx +12 -10
  46. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +12 -14
  47. package/src/components/UsaMap/components/Territory/TerritoryShape.ts +2 -1
  48. package/src/components/UsaMap/components/UsaMap.County.tsx +138 -96
  49. package/src/components/UsaMap/components/UsaMap.Region.styles.css +72 -0
  50. package/src/components/UsaMap/components/UsaMap.Region.tsx +56 -103
  51. package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +10 -0
  52. package/src/components/UsaMap/components/UsaMap.SingleState.tsx +65 -74
  53. package/src/components/UsaMap/components/UsaMap.State.tsx +112 -91
  54. package/src/components/UsaMap/helpers/map.ts +1 -1
  55. package/src/components/UsaMap/helpers/shapes.ts +20 -7
  56. package/src/components/WorldMap/WorldMap.tsx +64 -118
  57. package/src/components/WorldMap/worldMap.styles.css +28 -0
  58. package/src/components/ZoomControls.tsx +15 -13
  59. package/src/components/zoomControls.styles.css +53 -0
  60. package/src/context.ts +17 -9
  61. package/src/data/initial-state.js +5 -2
  62. package/src/helpers/addUIDs.ts +150 -0
  63. package/src/helpers/applyColorToLegend.ts +39 -64
  64. package/src/helpers/applyLegendToRow.ts +51 -0
  65. package/src/helpers/colorDistributions.ts +12 -0
  66. package/src/helpers/constants.ts +44 -0
  67. package/src/helpers/displayGeoName.ts +9 -2
  68. package/src/helpers/formatLegendLocation.ts +3 -2
  69. package/src/helpers/generateColorsArray.ts +2 -1
  70. package/src/helpers/generateRuntimeData.ts +78 -0
  71. package/src/helpers/generateRuntimeFilters.ts +63 -0
  72. package/src/helpers/generateRuntimeLegend.ts +566 -0
  73. package/src/helpers/generateRuntimeLegendHash.ts +16 -15
  74. package/src/helpers/getColumnNames.ts +19 -0
  75. package/src/helpers/getMapContainerClasses.ts +23 -0
  76. package/src/helpers/getStatePicked.ts +8 -0
  77. package/src/helpers/handleMapTabbing.ts +31 -0
  78. package/src/helpers/hashObj.ts +1 -1
  79. package/src/helpers/index.ts +22 -0
  80. package/src/helpers/navigationHandler.ts +3 -3
  81. package/src/helpers/resetLegendToggles.ts +13 -0
  82. package/src/helpers/setBinNumbers.ts +5 -0
  83. package/src/helpers/sortSpecialClassesLast.ts +7 -0
  84. package/src/helpers/tests/getColumnNames.test.ts +52 -0
  85. package/src/helpers/titleCase.ts +1 -1
  86. package/src/helpers/toggleLegendActive.ts +25 -0
  87. package/src/hooks/useApplyTooltipsToGeo.tsx +51 -0
  88. package/src/hooks/useColumnsRequiredChecker.ts +51 -0
  89. package/src/hooks/useGeoClickHandler.ts +45 -0
  90. package/src/hooks/useLegendSeparators.ts +26 -0
  91. package/src/hooks/useMapLayers.tsx +34 -60
  92. package/src/hooks/useModal.ts +22 -0
  93. package/src/hooks/useResizeObserver.ts +4 -5
  94. package/src/hooks/useStateZoom.tsx +52 -75
  95. package/src/hooks/useTooltip.ts +2 -3
  96. package/src/index.jsx +3 -9
  97. package/src/scss/editor-panel.scss +3 -99
  98. package/src/scss/main.scss +1 -19
  99. package/src/scss/map.scss +15 -220
  100. package/src/store/map.actions.ts +46 -0
  101. package/src/store/map.reducer.ts +96 -0
  102. package/src/types/Annotations.ts +24 -0
  103. package/src/types/MapConfig.ts +23 -3
  104. package/src/types/MapContext.ts +36 -35
  105. package/src/types/Modal.ts +1 -0
  106. package/src/types/RuntimeData.ts +3 -0
  107. package/examples/private/DEV-9644.json +0 -184
  108. package/examples/private/DEV-9989.json +0 -229
  109. package/examples/private/ardi.json +0 -180
  110. package/examples/private/colors 2.json +0 -416
  111. package/examples/private/colors.json +0 -416
  112. package/examples/private/colors.json.zip +0 -0
  113. package/examples/private/customColors.json +0 -45348
  114. package/examples/test.json +0 -183
  115. package/src/helpers/closeModal.ts +0 -9
  116. package/src/scss/btn.scss +0 -69
  117. package/src/scss/filters.scss +0 -27
  118. package/src/scss/variables.scss +0 -1
  119. /package/src/hooks/{useActiveElement.js → useActiveElement.ts} +0 -0
@@ -1,17 +1,16 @@
1
- import React, { useState, useEffect, useContext } from 'react'
1
+ import React, { useContext, useEffect, useState } from 'react'
2
2
 
3
3
  // Third Party
4
4
  import {
5
5
  Accordion,
6
6
  AccordionItem,
7
+ AccordionItemButton,
7
8
  AccordionItemHeading,
8
- AccordionItemPanel,
9
- AccordionItemButton
9
+ AccordionItemPanel
10
10
  } from 'react-accessible-accordion'
11
- import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
11
+ import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'
12
12
  import { useDebounce } from 'use-debounce'
13
13
  import _ from 'lodash'
14
- // import ReactTags from 'react-tag-autocomplete'
15
14
  import { Tooltip as ReactTooltip } from 'react-tooltip'
16
15
  import Panels from './Panels'
17
16
  import Layout from '@cdc/core/components/Layout'
@@ -39,83 +38,70 @@ import countyDefaultConfig from '../../../../examples/default-county.json'
39
38
  import useMapLayers from '../../../hooks/useMapLayers.tsx'
40
39
 
41
40
  import HexSetting from './HexShapeSettings.jsx'
42
- import ConfigContext from '../../../context.ts'
41
+ import ConfigContext, { MapDispatchContext } from '../../../context.ts'
43
42
  import { MapContext } from '../../../types/MapContext.js'
44
43
  import Alert from '@cdc/core/components/Alert'
45
44
  import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
46
45
  import { CheckBox, Select, TextField } from '@cdc/core/components/EditorPanel/Inputs'
46
+ import useColumnsRequiredChecker from '../../../hooks/useColumnsRequiredChecker'
47
+ import { addUIDs, HEADER_COLORS } from '../../../helpers'
48
+ import './editorPanel.styles.css'
49
+ import FootnotesEditor from '@cdc/core/components/EditorPanel/FootnotesEditor'
50
+ import { Datasets } from '@cdc/core/types/DataSet'
51
+
52
+ type MapEditorPanelProps = {
53
+ datasets?: Datasets
54
+ }
47
55
 
48
- // Todo: move to useReducer, seperate files out.
49
- const EditorPanel = ({ columnsRequiredChecker }) => {
50
- // prettier-ignore
56
+ const EditorPanel: React.FC<MapEditorPanelProps> = ({ datasets }) => {
51
57
  const {
58
+ setParentConfig,
52
59
  isDashboard,
53
- isDebug,
60
+ isEditor,
54
61
  loadConfig,
55
62
  runtimeFilters,
56
63
  runtimeLegend,
57
- setParentConfig,
58
- setState,
59
- state,
64
+ setConfig,
65
+ config,
60
66
  tooltipId,
61
67
  runtimeData,
62
- setRuntimeData,
63
- generateRuntimeData,
64
-
65
-
68
+ setRuntimeData
66
69
  } = useContext<MapContext>(ConfigContext)
67
70
 
68
- const { general, columns, legend, table, tooltips } = state
69
- const columnsInData = state?.data?.[0] ? Object.keys(state.data[0]) : []
70
-
71
- const [configTextboxValue, setConfigTextbox] = useState({}) // eslint-disable-line
71
+ const { columnsRequiredChecker } = useColumnsRequiredChecker()
72
+ const dispatch = useContext(MapDispatchContext)
73
+ const { general, columns, legend, table, tooltips } = config
74
+ const columnsInData = config?.data?.[0] ? Object.keys(config.data[0]) : []
72
75
 
73
76
  const [loadedDefault, setLoadedDefault] = useState(false)
74
-
75
77
  const [displayPanel, setDisplayPanel] = useState(true)
76
-
77
78
  const [activeFilterValueForDescription, setActiveFilterValueForDescription] = useState([0, 0])
78
79
 
79
- const headerColors = [
80
- 'theme-blue',
81
- 'theme-purple',
82
- 'theme-brown',
83
- 'theme-teal',
84
- 'theme-pink',
85
- 'theme-orange',
86
- 'theme-slate',
87
- 'theme-indigo',
88
- 'theme-cyan',
89
- 'theme-green',
90
- 'theme-amber'
91
- ]
92
-
93
80
  const {
94
- // prettier-ignore
95
- MapLayerHandlers: {
96
- handleMapLayer,
97
- handleAddLayer,
98
- handleRemoveLayer
81
+ MapLayerHandlers: { handleMapLayer, handleAddLayer, handleRemoveLayer }
82
+ } = useMapLayers(config, setConfig, false, tooltipId)
83
+
84
+ useEffect(() => {
85
+ // Pass up to Editor if needed
86
+ if (setParentConfig) {
87
+ setParentConfig(convertStateToConfig())
99
88
  }
100
- } = useMapLayers(state, setState, false, tooltipId)
89
+ }, [config])
101
90
 
102
91
  const categoryMove = (idx1, idx2) => {
103
92
  let categoryValuesOrder = getCategoryValuesOrder()
104
-
105
93
  let [movedItem] = categoryValuesOrder.splice(idx1, 1)
106
-
107
94
  categoryValuesOrder.splice(idx2, 0, movedItem)
108
-
109
- state.legend.categoryValuesOrder?.forEach(value => {
95
+ config.legend.categoryValuesOrder?.forEach(value => {
110
96
  if (categoryValuesOrder.indexOf(value) === -1) {
111
97
  categoryValuesOrder.push(value)
112
98
  }
113
99
  })
114
100
 
115
- setState({
116
- ...state,
101
+ setConfig({
102
+ ...config,
117
103
  legend: {
118
- ...state.legend,
104
+ ...config.legend,
119
105
  categoryValuesOrder
120
106
  }
121
107
  })
@@ -125,16 +111,16 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
125
111
  if (legend.specialClasses && legend.specialClasses.length && typeof legend.specialClasses[0] === 'string') {
126
112
  legend.specialClasses.forEach(specialClass => {
127
113
  specialClasses.push({
128
- key: state.columns.primary && state.columns.primary.name ? state.columns.primary.name : columnsInData[0],
114
+ key: config.columns.primary && config.columns.primary.name ? config.columns.primary.name : columnsInData[0],
129
115
  value: specialClass,
130
116
  label: specialClass
131
117
  })
132
118
  })
133
119
  // DEV-3303 - since the above was a repair of bad config - need to backpopulate into the state
134
- setState({
135
- ...state,
120
+ setConfig({
121
+ ...config,
136
122
  legend: {
137
- ...state.legend,
123
+ ...config.legend,
138
124
  specialClasses: specialClasses
139
125
  }
140
126
  })
@@ -142,12 +128,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
142
128
  specialClasses = legend.specialClasses || []
143
129
  }
144
130
 
131
+ const allowLegendSeparators = legend.style === 'gradient' && legend.subStyle === 'linear blocks'
132
+
145
133
  const getCityStyleOptions = target => {
146
134
  switch (target) {
147
135
  case 'value': {
148
136
  const values = ['Circle', 'Square', 'Triangle', 'Diamond', 'Star', 'Pin']
149
137
  const filteredValues = values.filter(
150
- val => String(state.visual.cityStyle).toLocaleLowerCase() !== val.toLocaleLowerCase()
138
+ val => String(config.visual.cityStyle).toLocaleLowerCase() !== val.toLocaleLowerCase()
151
139
  )
152
140
 
153
141
  return (
@@ -171,12 +159,12 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
171
159
  const editCityStyles = (target, index, fieldName, value) => {
172
160
  switch (target) {
173
161
  case 'add': {
174
- const additionalCityStyles = state.visual.additionalCityStyles ? [...state.visual.additionalCityStyles] : []
162
+ const additionalCityStyles = config.visual.additionalCityStyles ? [...config.visual.additionalCityStyles] : []
175
163
  additionalCityStyles.push({ label: '', column: '', value: '', shape: '' })
176
- setState({
177
- ...state,
164
+ setConfig({
165
+ ...config,
178
166
  visual: {
179
- ...state.visual,
167
+ ...config.visual,
180
168
  additionalCityStyles: additionalCityStyles
181
169
  }
182
170
  })
@@ -184,15 +172,15 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
184
172
  }
185
173
  case 'remove': {
186
174
  let additionalCityStyles = []
187
- if (state.visual.additionalCityStyles) {
188
- additionalCityStyles = [...state.visual.additionalCityStyles]
175
+ if (config.visual.additionalCityStyles) {
176
+ additionalCityStyles = [...config.visual.additionalCityStyles]
189
177
  }
190
178
 
191
179
  additionalCityStyles.splice(index, 1)
192
- setState({
193
- ...state,
180
+ setConfig({
181
+ ...config,
194
182
  visual: {
195
- ...state.visual,
183
+ ...config.visual,
196
184
  additionalCityStyles: additionalCityStyles
197
185
  }
198
186
  })
@@ -200,12 +188,12 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
200
188
  }
201
189
  case 'update': {
202
190
  let additionalCityStyles = []
203
- additionalCityStyles = [...state.visual.additionalCityStyles]
191
+ additionalCityStyles = [...config.visual.additionalCityStyles]
204
192
  additionalCityStyles[index][fieldName] = value
205
- setState({
206
- ...state,
193
+ setConfig({
194
+ ...config,
207
195
  visual: {
208
- ...state.visual,
196
+ ...config.visual,
209
197
  additionalCityStyles: additionalCityStyles
210
198
  }
211
199
  })
@@ -222,7 +210,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
222
210
  if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
223
211
  handleEditorChanges('changeLegendDescription', [String(activeFilterValueForDescription), debouncedValue])
224
212
  }
225
- }, [debouncedValue]) // eslint-disable-line
213
+ }, [debouncedValue])
226
214
 
227
215
  const onChange = e => setValue(e.target.value)
228
216
 
@@ -231,277 +219,150 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
231
219
 
232
220
  const handleEditorChanges = async (property, value) => {
233
221
  switch (property) {
234
- case 'navigationTarget':
235
- setState({
236
- ...state,
237
- general: {
238
- ...state.general,
239
- navigationTarget: value
240
- }
241
- })
242
- break
243
- // change these to be more generic.
244
- // updateVisualPropertyValue
245
- // updateGeneralPropertyValue, etc.
246
- case 'showBubbleZeros':
247
- setState({
248
- ...state,
249
- visual: {
250
- ...state.visual,
251
- showBubbleZeros: value
252
- }
253
- })
254
- break
255
- case 'showEqualNumber':
256
- setState({
257
- ...state,
258
- general: {
259
- ...state.general,
260
- equalNumberOptIn: value
261
- }
262
- })
263
- break
264
- case 'hideGeoColumnInTooltip':
265
- setState({
266
- ...state,
267
- general: {
268
- ...state.general,
269
- [property]: value
270
- }
271
- })
272
- break
273
-
274
- case 'toggleDataTableLink':
275
- setState({
276
- ...state,
277
- table: {
278
- ...state.table,
279
- showDataTableLink: value
280
- }
281
- })
282
- break
283
-
284
- case 'toggleDataUrl':
285
- setState({
286
- ...state,
287
- table: {
288
- ...state.table,
289
- showDownloadUrl: value
290
- }
291
- })
292
- break
293
- case 'toggleExtraBubbleBorder':
294
- setState({
295
- ...state,
296
- visual: {
297
- ...state.visual,
298
- extraBubbleBorder: value
299
- }
300
- })
301
- break
302
- case 'allowMapZoom':
303
- setState({
304
- ...state,
305
- general: {
306
- ...state.general,
307
- allowMapZoom: value
308
- },
309
- mapPosition: {
310
- coordinates: state.general.geoType === 'world' ? [0, 30] : [0, 0],
311
- zoom: 1
312
- }
313
- })
314
- break
315
222
  case 'hidePrimaryColumnInTooltip':
316
- setState({
317
- ...state,
223
+ setConfig({
224
+ ...config,
318
225
  general: {
319
- ...state.general,
226
+ ...config.general,
320
227
  [property]: value
321
228
  }
322
229
  })
323
230
  break
324
231
  case 'geoLabelOverride':
325
- setState({
326
- ...state,
232
+ setConfig({
233
+ ...config,
327
234
  general: {
328
- ...state.general,
235
+ ...config.general,
329
236
  geoLabelOverride: value
330
237
  }
331
238
  })
332
239
  break
333
240
  case 'showTitle':
334
- setState({
335
- ...state,
241
+ setConfig({
242
+ ...config,
336
243
  general: {
337
- ...state.general,
244
+ ...config.general,
338
245
  showTitle: value
339
246
  }
340
247
  })
341
248
  break
342
- case 'showSidebar':
343
- setState({
344
- ...state,
345
- general: {
346
- ...state.general,
347
- showSidebar: value
348
- }
349
- })
350
- break
351
- case 'fullBorder':
352
- setState({
353
- ...state,
354
- general: {
355
- ...state.general,
356
- fullBorder: value
357
- }
358
- })
359
- break
360
249
  case 'expandDataTable':
361
- setState({
362
- ...state,
250
+ setConfig({
251
+ ...config,
363
252
  table: {
364
- ...state.table,
253
+ ...config.table,
365
254
  expanded: value
366
255
  }
367
256
  })
368
257
  break
369
- case 'color':
370
- setState({
371
- ...state,
372
- color: value
373
- })
374
- break
375
258
  case 'sidebarPosition':
376
- setState({
377
- ...state,
259
+ setConfig({
260
+ ...config,
378
261
  legend: {
379
- ...state.legend,
262
+ ...config.legend,
380
263
  position: value,
381
264
  hideBorder: _.includes(['top', 'bottom'], value)
382
265
  }
383
266
  })
384
267
  break
385
268
  case 'legendStyle':
386
- setState({
387
- ...state,
269
+ setConfig({
270
+ ...config,
388
271
  legend: {
389
- ...state.legend,
272
+ ...config.legend,
390
273
  style: value
391
274
  }
392
275
  })
393
276
  break
394
277
  case 'legendSubStyle':
395
- setState({
396
- ...state,
278
+ setConfig({
279
+ ...config,
397
280
  legend: {
398
- ...state.legend,
281
+ ...config.legend,
399
282
  subStyle: value
400
283
  }
401
284
  })
402
285
  break
286
+ case 'legendGroupBy':
287
+ setConfig({
288
+ ...config,
289
+ legend: {
290
+ ...config.legend,
291
+ groupBy: value
292
+ }
293
+ })
294
+ break
403
295
  case 'legendTickRotation':
404
- setState({
405
- ...state,
296
+ setConfig({
297
+ ...config,
406
298
  legend: {
407
- ...state.legend,
299
+ ...config.legend,
408
300
  tickRotation: value
409
301
  }
410
302
  })
411
303
  break
412
304
  case 'legendBorder':
413
- setState({
414
- ...state,
305
+ setConfig({
306
+ ...config,
415
307
  legend: {
416
- ...state.legend,
308
+ ...config.legend,
417
309
  hideBorder: value
418
310
  }
419
311
  })
420
312
  break
421
313
  case 'handleCityStyle':
422
- setState({
423
- ...state,
314
+ setConfig({
315
+ ...config,
424
316
  visual: {
425
- ...state.visual,
317
+ ...config.visual,
426
318
  cityStyle: value
427
319
  }
428
320
  })
429
321
  break
430
322
  case 'geoBorderColor':
431
- setState({
432
- ...state,
323
+ setConfig({
324
+ ...config,
433
325
  general: {
434
- ...state.general,
326
+ ...config.general,
435
327
  geoBorderColor: value
436
328
  }
437
329
  })
438
330
  break
439
331
  case 'headerColor':
440
- setState({
441
- ...state,
332
+ setConfig({
333
+ ...config,
442
334
  general: {
443
- ...state.general,
335
+ ...config.general,
444
336
  headerColor: value
445
337
  }
446
338
  })
447
339
  break
448
340
  case 'navigateColumn':
449
- setState({
450
- ...state,
341
+ setConfig({
342
+ ...config,
451
343
  columns: {
452
- ...state.columns,
344
+ ...config.columns,
453
345
  navigate: {
454
- ...state.columns.navigate,
346
+ ...config.columns.navigate,
455
347
  name: value
456
348
  }
457
349
  }
458
350
  })
459
351
  break
460
352
  case 'legendDescription':
461
- setState({
462
- ...state,
353
+ setConfig({
354
+ ...config,
463
355
  legend: {
464
- ...state.legend,
356
+ ...config.legend,
465
357
  description: value
466
358
  }
467
359
  })
468
360
  break
469
- case 'legendType':
470
- let testForType = Number(typeof state.data[0][state.columns.primary.name])
471
- let hasValue = state.data[0][state.columns.primary.name]
472
- let messages = []
473
-
474
- if (!hasValue) {
475
- messages.push(
476
- `There appears to be values missing for data in the primary column ${state.columns.primary.name}`
477
- )
478
- }
479
-
480
- if (testForType === 'string' && isNaN(testForType) && value !== 'category') {
481
- messages.push(
482
- 'Error with legend. Primary columns that are text must use a categorical legend type. Try changing the legend type to DEV-12345categorical.'
483
- )
484
- } else {
485
- messages = []
486
- }
487
-
488
- setState({
489
- ...state,
490
- legend: {
491
- ...state.legend,
492
- type: value
493
- },
494
- runtime: {
495
- ...state.runtime,
496
- editorErrorMessage: messages
497
- }
498
- })
499
- break
500
361
  case 'legendNumber':
501
- setState({
502
- ...state,
362
+ setConfig({
363
+ ...config,
503
364
  legend: {
504
- ...state.legend,
365
+ ...config.legend,
505
366
  numberOfItems: parseInt(value)
506
367
  }
507
368
  })
@@ -512,123 +373,105 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
512
373
  setActiveFilterValueForDescription(arrVal)
513
374
  break
514
375
  case 'unifiedLegend':
515
- setState({
516
- ...state,
376
+ setConfig({
377
+ ...config,
517
378
  legend: {
518
- ...state.legend,
379
+ ...config.legend,
519
380
  unified: value
520
381
  }
521
382
  })
522
383
  break
523
- case 'separateZero':
524
- setState({
525
- ...state,
526
- legend: {
527
- ...state.legend,
528
- separateZero: value
529
- }
530
- })
531
- break
532
384
  case 'toggleShowFullGeoNameInCSV':
533
- setState({
534
- ...state,
385
+ setConfig({
386
+ ...config,
535
387
  table: {
536
388
  // setting both bc DataTable new core needs it here
537
- ...state.table,
538
- showFullGeoNameInCSV: !state.table.showFullGeoNameInCSV
389
+ ...config.table,
390
+ showFullGeoNameInCSV: !config.table.showFullGeoNameInCSV
539
391
  }
540
392
  })
541
393
  break
542
394
  case 'toggleDownloadImgButton':
543
- setState({
544
- ...state,
395
+ setConfig({
396
+ ...config,
545
397
  general: {
546
- ...state.general,
547
- showDownloadImgButton: !state.general.showDownloadImgButton
398
+ ...config.general,
399
+ showDownloadImgButton: !config.general.showDownloadImgButton
548
400
  }
549
401
  })
550
402
  break
551
403
  case 'toggleDownloadLinkBelow':
552
- setState({
553
- ...state,
404
+ setConfig({
405
+ ...config,
554
406
  table: {
555
- ...state.table,
556
- showDownloadLinkBelow: !state.table.showDownloadLinkBelow
407
+ ...config.table,
408
+ showDownloadLinkBelow: !config.table.showDownloadLinkBelow
557
409
  }
558
410
  })
559
411
  break
560
412
  case 'toggleDownloadPdfButton':
561
- setState({
562
- ...state,
563
- general: {
564
- ...state.general,
565
- showDownloadPdfButton: !state.general.showDownloadPdfButton
566
- }
567
- })
568
- break
569
- case 'displayAsHex':
570
- setState({
571
- ...state,
413
+ setConfig({
414
+ ...config,
572
415
  general: {
573
- ...state.general,
574
- displayAsHex: value
416
+ ...config.general,
417
+ showDownloadPdfButton: !config.general.showDownloadPdfButton
575
418
  }
576
419
  })
577
420
  break
578
421
  case 'editorMapType':
579
422
  switch (value) {
580
423
  case 'us-geocode':
581
- setState({
582
- ...state,
424
+ setConfig({
425
+ ...config,
583
426
  general: {
584
- ...state.general,
427
+ ...config.general,
585
428
  type: value
586
429
  }
587
430
  })
588
431
  break
589
432
  case 'world-geocode':
590
- setState({
591
- ...state,
433
+ setConfig({
434
+ ...config,
592
435
  general: {
593
- ...state.general,
436
+ ...config.general,
594
437
  type: value
595
438
  }
596
439
  })
597
440
  break
598
441
  case 'data':
599
- setState({
600
- ...state,
442
+ setConfig({
443
+ ...config,
601
444
  general: {
602
- ...state.general,
445
+ ...config.general,
603
446
  showSidebar: true,
604
447
  type: 'data'
605
448
  }
606
449
  })
607
450
  break
608
451
  case 'navigation':
609
- setState({
610
- ...state,
452
+ setConfig({
453
+ ...config,
611
454
  general: {
612
- ...state.general,
455
+ ...config.general,
613
456
  showSidebar: false,
614
457
  type: 'navigation'
615
458
  },
616
459
  tooltips: {
617
- ...state.tooltips,
460
+ ...config.tooltips,
618
461
  appearanceType: 'hover'
619
462
  }
620
463
  })
621
464
  break
622
465
  case 'bubble':
623
- setState({
624
- ...state,
466
+ setConfig({
467
+ ...config,
625
468
  general: {
626
- ...state.general,
469
+ ...config.general,
627
470
  showSidebar: false,
628
471
  type: 'bubble'
629
472
  },
630
473
  tooltips: {
631
- ...state.tooltips,
474
+ ...config.tooltips,
632
475
  appearanceType: 'hover'
633
476
  }
634
477
  })
@@ -639,6 +482,9 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
639
482
  }
640
483
  break
641
484
  case 'geoType':
485
+ addUIDs(config, config.columns.geo.name)
486
+ dispatch({ type: 'SET_POSITION', payload: [0, 30] })
487
+
642
488
  // If we're still working with default data, switch to the world default to show it as an example
643
489
  if (true === loadedDefault && 'world' === value) {
644
490
  loadConfig(worldDefaultConfig)
@@ -657,78 +503,78 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
657
503
 
658
504
  switch (value) {
659
505
  case 'us':
660
- setState({
661
- ...state,
506
+ setConfig({
507
+ ...config,
662
508
  general: {
663
- ...state.general,
509
+ ...config.general,
664
510
  geoType: 'us',
665
- type: state.type === 'us-geocode' ? 'data' : state.type
511
+ type: config.type === 'us-geocode' ? 'data' : config.type
666
512
  },
667
513
  table: {
668
- ...state.table,
514
+ ...config.table,
669
515
  forceDisplay: true
670
516
  }
671
517
  })
672
518
  break
673
519
  case 'us-region':
674
- setState({
675
- ...state,
520
+ setConfig({
521
+ ...config,
676
522
  general: {
677
- ...state.general,
523
+ ...config.general,
678
524
  geoType: 'us-region'
679
525
  },
680
526
  table: {
681
- ...state.table,
527
+ ...config.table,
682
528
  forceDisplay: true
683
529
  }
684
530
  })
685
531
  break
686
532
  case 'world':
687
- setState({
688
- ...state,
533
+ setConfig({
534
+ ...config,
689
535
  general: {
690
- ...state.general,
536
+ ...config.general,
691
537
  geoType: 'world'
692
538
  },
693
539
  table: {
694
- ...state.table,
540
+ ...config.table,
695
541
  forceDisplay: true
696
542
  }
697
543
  })
698
544
  break
699
545
  case 'us-county':
700
- setState({
701
- ...state,
546
+ setConfig({
547
+ ...config,
702
548
  general: {
703
- ...state.general,
549
+ ...config.general,
704
550
  geoType: 'us-county'
705
551
  },
706
552
  table: {
707
- ...state.table,
553
+ ...config.table,
708
554
  expanded: false,
709
555
  forceDisplay: true
710
556
  }
711
557
  })
712
558
  break
713
559
  case 'single-state':
714
- setState({
715
- ...state,
560
+ setConfig({
561
+ ...config,
716
562
  general: {
717
- ...state.general,
563
+ ...config.general,
718
564
  geoType: 'single-state'
719
565
  },
720
566
  table: {
721
- ...state.table,
567
+ ...config.table,
722
568
  expanded: false,
723
569
  forceDisplay: true
724
570
  }
725
571
  })
726
572
  break
727
573
  case 'google-map':
728
- setState({
729
- ...state,
574
+ setConfig({
575
+ ...config,
730
576
  general: {
731
- ...state.general,
577
+ ...config.general,
732
578
  geoType: 'google-map'
733
579
  }
734
580
  })
@@ -736,125 +582,103 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
736
582
  break
737
583
  }
738
584
 
739
- break
740
- case 'singleColumnLegend':
741
- setState({
742
- ...state,
743
- legend: {
744
- ...state.legend,
745
- singleColumn: !state.legend.singleColumn,
746
- singleRow: false,
747
- verticalSorted: false
748
- }
749
- })
750
- break
751
- case 'singleRowLegend':
752
- setState({
753
- ...state,
754
- legend: {
755
- ...state.legend,
756
- singleRow: !state.legend.singleRow,
757
- singleColumn: false,
758
- verticalSorted: false
759
- }
760
- })
761
585
  break
762
586
  case 'verticalSortedLegend':
763
- setState({
764
- ...state,
587
+ setConfig({
588
+ ...config,
765
589
  legend: {
766
- ...state.legend,
767
- verticalSorted: !state.legend.verticalSorted,
590
+ ...config.legend,
591
+ verticalSorted: !config.legend.verticalSorted,
768
592
  singleRow: false,
769
593
  singleColumn: false
770
594
  }
771
595
  })
772
596
  break
773
597
  case 'legendShowSpecialClassesLast':
774
- setState({
775
- ...state,
598
+ setConfig({
599
+ ...config,
776
600
  legend: {
777
- ...state.legend,
778
- showSpecialClassesLast: !state.legend.showSpecialClassesLast
601
+ ...config.legend,
602
+ showSpecialClassesLast: !config.legend.showSpecialClassesLast
779
603
  }
780
604
  })
781
605
  break
782
606
  case 'dynamicDescription':
783
- setState({
784
- ...state,
607
+ setConfig({
608
+ ...config,
785
609
  editor: {
786
- ...state.editor,
610
+ ...config.editor,
787
611
  activeFilterValueForDescription: value
788
612
  },
789
613
  legend: {
790
- ...state.legend,
791
- dynamicDescription: !state.legend.dynamicDescription
614
+ ...config.legend,
615
+ dynamicDescription: !config.legend.dynamicDescription
792
616
  }
793
617
  })
794
618
  break
795
619
  case 'changeLegendDescription':
796
620
  const [filterValKey, filterValDesc] = value
797
- setState({
798
- ...state,
621
+ setConfig({
622
+ ...config,
799
623
  legend: {
800
- ...state.legend,
624
+ ...config.legend,
801
625
  descriptions: {
802
- ...state.legend.descriptions,
626
+ ...config.legend.descriptions,
803
627
  [filterValKey]: [filterValDesc]
804
628
  }
805
629
  }
806
630
  })
807
631
  break
808
632
  case 'appearanceType':
809
- setState({
810
- ...state,
633
+ setConfig({
634
+ ...config,
811
635
  tooltips: {
812
- ...state.tooltips,
636
+ ...config.tooltips,
813
637
  appearanceType: value
814
638
  }
815
639
  })
816
640
  break
817
641
  case 'linkLabel':
818
- setState({
819
- ...state,
642
+ setConfig({
643
+ ...config,
820
644
  tooltips: {
821
- ...state.tooltips,
645
+ ...config.tooltips,
822
646
  linkLabel: value
823
647
  }
824
648
  })
825
649
  break
826
650
  case 'displayStateLabels':
827
- setState({
828
- ...state,
651
+ setConfig({
652
+ ...config,
829
653
  general: {
830
- ...state.general,
831
- displayStateLabels: !state.general.displayStateLabels
654
+ ...config.general,
655
+ displayStateLabels: !config.general.displayStateLabels
832
656
  }
833
657
  })
834
658
  break
835
659
  case 'capitalizeLabels':
836
- setState({
837
- ...state,
660
+ setConfig({
661
+ ...config,
838
662
  tooltips: {
839
- ...state.tooltips,
663
+ ...config.tooltips,
840
664
  capitalizeLabels: value
841
665
  }
842
666
  })
843
667
  break
844
668
  case 'showDataTable':
845
- setState({
846
- ...state,
669
+ setConfig({
670
+ ...config,
847
671
  table: {
848
- ...state.table,
672
+ ...config.table,
849
673
  forceDisplay: value
850
674
  }
851
675
  })
852
676
  break
853
677
  case 'limitDataTableHeight':
854
- setState({
855
- ...state,
678
+ setConfig({
679
+ ...config,
856
680
  table: {
857
- ...state.table,
681
+ ...config.table,
858
682
  limitHeight: value
859
683
  }
860
684
  })
@@ -864,67 +688,58 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
864
688
  let stateName = value
865
689
  let stateData = { fipsCode, stateName }
866
690
 
867
- setState({
868
- ...state,
691
+ setConfig({
692
+ ...config,
869
693
  general: {
870
- ...state.general,
694
+ ...config.general,
871
695
  statePicked: stateData
872
696
  }
873
697
  })
874
698
 
875
- if (state) {
876
- const newData = generateRuntimeData(state)
699
+ if (config) {
700
+ const newData = generateRuntimeData(config)
877
701
  setRuntimeData(newData)
878
702
  }
879
703
  break
880
704
  case 'classificationType':
881
- setState({
882
- ...state,
705
+ setConfig({
706
+ ...config,
883
707
  legend: {
884
- ...state.legend,
708
+ ...config.legend,
885
709
  type: value
886
710
  }
887
711
  })
888
712
  break
889
- case 'territoriesAlwaysShow':
890
- setState({
891
- ...state,
892
- general: {
893
- ...state.general,
894
- territoriesAlwaysShow: value
895
- }
896
- })
897
- break
898
713
  case 'countyCensusYear':
899
- setState({
900
- ...state,
714
+ setConfig({
715
+ ...config,
901
716
  general: {
902
- ...state.general,
717
+ ...config.general,
903
718
  countyCensusYear: value
904
719
  }
905
720
  })
906
721
  break
907
722
  case 'filterControlsCountyYear':
908
- setState({
909
- ...state,
723
+ setConfig({
724
+ ...config,
910
725
  general: {
911
- ...state.general,
726
+ ...config.general,
912
727
  filterControlsCountyYear: value
913
728
  }
914
729
  })
915
730
  break
916
731
  case 'filterControlsStatePicked':
917
- setState({
918
- ...state,
732
+ setConfig({
733
+ ...config,
919
734
  general: {
920
- ...state.general,
735
+ ...config.general,
921
736
  filterControlsStatePicked: value
922
737
  }
923
738
  })
924
739
  break
925
740
  case 'filterBehavior':
926
- setState({
927
- ...state,
741
+ setConfig({
742
+ ...config,
928
743
  filterBehavior: value
929
744
  })
930
745
  break
@@ -942,10 +757,10 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
942
757
 
943
758
  newSpecialClasses[value.index][value.prop] = value.value
944
759
 
945
- setState({
946
- ...state,
760
+ setConfig({
761
+ ...config,
947
762
  legend: {
948
- ...state.legend,
763
+ ...config.legend,
949
764
  specialClasses: newSpecialClasses
950
765
  }
951
766
  })
@@ -955,10 +770,10 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
955
770
 
956
771
  newSpecialClasses.splice(value, 1)
957
772
 
958
- setState({
959
- ...state,
773
+ setConfig({
774
+ ...config,
960
775
  legend: {
961
- ...state.legend,
776
+ ...config.legend,
962
777
  specialClasses: newSpecialClasses
963
778
  }
964
779
  })
@@ -968,21 +783,22 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
968
783
 
969
784
  newSpecialClasses.push(value)
970
785
 
971
- setState({
972
- ...state,
786
+ setConfig({
787
+ ...config,
973
788
  legend: {
974
- ...state.legend,
789
+ ...config.legend,
975
790
  specialClasses: newSpecialClasses
976
791
  }
977
792
  })
978
793
  break
979
794
  case 'name':
980
- setState({
981
- ...state,
795
+ addUIDs(config, config.columns.geo.name)
796
+ setConfig({
797
+ ...config,
982
798
  columns: {
983
- ...state.columns,
799
+ ...config.columns,
984
800
  [columnName]: {
985
- ...state.columns[columnName],
801
+ ...config.columns[columnName],
986
802
  [editTarget]: value
987
803
  }
988
804
  }
@@ -990,12 +806,12 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
990
806
 
991
807
  break
992
808
  default:
993
- setState({
994
- ...state,
809
+ setConfig({
810
+ ...config,
995
811
  columns: {
996
- ...state.columns,
812
+ ...config.columns,
997
813
  [columnName]: {
998
- ...state.columns[columnName],
814
+ ...config.columns[columnName],
999
815
  [editTarget]: value
1000
816
  }
1001
817
  }
@@ -1004,71 +820,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1004
820
  }
1005
821
  }
1006
822
 
1007
- const changeFilter = async (idx, target, value) => {
1008
- let newFilters = [...state.filters]
1009
-
1010
- switch (target) {
1011
- case 'addNew':
1012
- newFilters.push({
1013
- label: '',
1014
- values: []
1015
- })
1016
- break
1017
- case 'remove':
1018
- if (newFilters.length === 1) {
1019
- newFilters = []
1020
- } else {
1021
- newFilters.splice(idx, 1)
1022
- }
1023
- break
1024
- case 'filterStyle':
1025
- newFilters[idx] = { ...newFilters[idx] }
1026
- newFilters[idx].filterStyle = value
1027
- break
1028
- case 'showDropdown':
1029
- newFilters[idx] = { ...newFilters[idx] }
1030
- newFilters[idx].showDropdown = value
1031
- break
1032
- case 'columnName':
1033
- newFilters[idx] = { ...newFilters[idx] }
1034
- newFilters[idx].columnName = value
1035
- newFilters[idx].values = [] // when a column name changes knock the previous values out
1036
- break
1037
- case 'filterOrder':
1038
- if (value === 'desc') {
1039
- newFilters[idx] = { ...runtimeFilters[idx] }
1040
- delete newFilters[idx].active
1041
- newFilters[idx].order = 'desc'
1042
- }
1043
- if (value === 'asc') {
1044
- newFilters[idx] = { ...runtimeFilters[idx] }
1045
- delete newFilters[idx].active
1046
- newFilters[idx].order = 'asc'
1047
- }
1048
- if (value === 'cust') {
1049
- newFilters[idx] = { ...runtimeFilters[idx] }
1050
- newFilters[idx].order = 'cust'
1051
- }
1052
- break
1053
- default:
1054
- newFilters[idx][target] = value
1055
- break
1056
- }
1057
-
1058
- setState({
1059
- ...state,
1060
- filters: newFilters
1061
- })
1062
- }
1063
-
1064
823
  // just adds a new column but not set to any data yet
1065
824
  const addAdditionalColumn = number => {
1066
825
  const columnKey = `additionalColumn${number}`
1067
826
 
1068
- setState({
1069
- ...state,
827
+ setConfig({
828
+ ...config,
1070
829
  columns: {
1071
- ...state.columns,
830
+ ...config.columns,
1072
831
  [columnKey]: {
1073
832
  label: 'New Column',
1074
833
  dataTable: false,
@@ -1081,18 +840,18 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1081
840
  }
1082
841
 
1083
842
  const removeAdditionalColumn = columnName => {
1084
- const newColumns = state.columns
843
+ const newColumns = config.columns
1085
844
 
1086
845
  delete newColumns[columnName]
1087
846
 
1088
- setState({
1089
- ...state,
847
+ setConfig({
848
+ ...config,
1090
849
  columns: newColumns
1091
850
  })
1092
851
  }
1093
852
 
1094
853
  const displayFilterLegendValue = arr => {
1095
- const filterName = state.filters[arr[0]].label || `Unlabeled Legend`
854
+ const filterName = config.filters?.[arr?.[0]]?.label || `Unlabeled Legend`
1096
855
 
1097
856
  const filterValue = runtimeFilters[arr[0]]
1098
857
 
@@ -1116,15 +875,17 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1116
875
  }
1117
876
 
1118
877
  const convertStateToConfig = () => {
1119
- let strippedState = _.cloneDeep(state) // Deep copy
878
+ let strippedState = _.cloneDeep(config) // Deep copy
1120
879
 
1121
880
  // Strip ref
1122
881
  delete strippedState['']
1123
882
 
1124
- delete strippedState.newViz
883
+ if (strippedState.columns.geo.name && strippedState.columns.primary.name) {
884
+ delete strippedState.newViz
885
+ }
1125
886
 
1126
887
  // Remove the legend
1127
- let strippedLegend = _.cloneDeep(state.legend)
888
+ let strippedLegend = _.cloneDeep(config.legend)
1128
889
 
1129
890
  delete strippedLegend.disabledAmt
1130
891
 
@@ -1134,19 +895,18 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1134
895
  delete strippedState.defaultData
1135
896
 
1136
897
  // Remove tooltips if they're active in the editor
1137
- let strippedGeneral = _.cloneDeep(state.general)
1138
-
1139
- strippedState.general = strippedGeneral
898
+ strippedState.general = _.cloneDeep(config.general)
1140
899
 
1141
900
  // Add columns property back to data if it's there
1142
- if (state.columns) {
1143
- strippedState.columns = state.columns
901
+ if (config.columns) {
902
+ strippedState.columns = config.columns
1144
903
  }
1145
904
 
1146
905
  return strippedState
1147
906
  }
1148
907
 
1149
- const isReversed = state.general.palette.isReversed
908
+ const isReversed = config.general.palette.isReversed
909
+
1150
910
  function filterColorPalettes() {
1151
911
  let sequential = []
1152
912
  let nonSequential = []
@@ -1189,23 +949,16 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1189
949
  const [sequential, nonSequential, accessibleColors] = filterColorPalettes()
1190
950
 
1191
951
  useEffect(() => {
1192
- let paletteName = ''
1193
- if (isReversed && !state.color.endsWith('reverse')) {
1194
- paletteName = state.color + 'reverse'
1195
- }
1196
- if (!isReversed && state.color.endsWith('reverse')) {
1197
- paletteName = state.color.slice(0, -7)
1198
- }
1199
- if (paletteName) {
1200
- handleEditorChanges('color', paletteName)
1201
- }
1202
- }, [isReversed])
952
+ setLoadedDefault(config.defaultData)
953
+ columnsRequiredChecker()
954
+ }, [config])
1203
955
 
1204
956
  useEffect(() => {
1205
- setLoadedDefault(state.defaultData)
1206
-
1207
- columnsRequiredChecker()
1208
- }, [state]) // eslint-disable-line
957
+ const newConfig = convertStateToConfig()
958
+ if (isEditor && setParentConfig) {
959
+ setParentConfig(newConfig)
960
+ }
961
+ }, [config])
1209
962
 
1210
963
  const columnsOptions = [
1211
964
  <option value='' key={'Select Option'}>
@@ -1222,7 +975,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1222
975
  })
1223
976
 
1224
977
  let columnsByKey = {}
1225
- state.data.forEach(datum => {
978
+ config.data.forEach(datum => {
1226
979
  Object.keys(datum).forEach(key => {
1227
980
  columnsByKey[key] = columnsByKey[key] || []
1228
981
  const value = typeof datum[key] === 'number' ? datum[key].toString() : datum[key]
@@ -1233,27 +986,22 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1233
986
  })
1234
987
  })
1235
988
 
1236
- const additionalColumns = Object.keys(state.columns).filter(value => {
989
+ const additionalColumns = Object.keys(config.columns).filter(value => {
1237
990
  const defaultCols = ['geo', 'navigate', 'primary', 'latitude', 'longitude']
1238
991
 
1239
- if (true === defaultCols.includes(value)) {
1240
- return false
1241
- }
1242
- return true
992
+ return true !== defaultCols.includes(value)
1243
993
  })
1244
994
 
1245
- const updateField = updateFieldFactory(state, setState)
995
+ const updateField = updateFieldFactory(config, setConfig)
1246
996
 
1247
997
  const onBackClick = () => {
1248
998
  setDisplayPanel(!displayPanel)
1249
- setState({
1250
- ...state,
999
+ setConfig({
1000
+ ...config,
1251
1001
  showEditorPanel: !displayPanel
1252
1002
  })
1253
1003
  }
1254
1004
 
1255
- const usedFilterColumns = {}
1256
-
1257
1005
  const StateOptionList = () => {
1258
1006
  const arrOfArrays = Object.entries(supportedStatesFipsCodes)
1259
1007
 
@@ -1283,36 +1031,22 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1283
1031
  })
1284
1032
  }
1285
1033
 
1286
- useEffect(() => {
1287
- const parsedData = convertStateToConfig()
1288
- const formattedData = JSON.stringify(parsedData, undefined, 2)
1289
-
1290
- setConfigTextbox(formattedData)
1291
- }, [state]) // eslint-disable-line
1292
-
1293
- useEffect(() => {
1294
- // Pass up to Editor if needed
1295
- if (setParentConfig) {
1296
- const newConfig = convertStateToConfig()
1297
- setParentConfig(newConfig)
1298
- }
1299
- }, [state]) // eslint-disable-line
1300
-
1301
1034
  let numberOfItemsLimit = 8
1302
1035
 
1303
1036
  const getItemStyle = (isDragging, draggableStyle) => ({
1304
1037
  ...draggableStyle
1305
1038
  })
1306
1039
 
1307
- const getCategoryValuesOrder = () => {
1308
- let values = runtimeLegend
1309
- ? runtimeLegend.filter(item => !item.special).map(runtimeLegendItem => runtimeLegendItem.value)
1310
- : []
1040
+ const getCategoryValuesOrder = (): string[] | [] => {
1041
+ let values =
1042
+ runtimeLegend?.items?.length > 0
1043
+ ? runtimeLegend.items.filter(item => !item.special).map(runtimeLegendItem => runtimeLegendItem.value)
1044
+ : []
1311
1045
 
1312
- if (state.legend.cateogryValuesOrder) {
1046
+ if (config.legend.cateogryValuesOrder) {
1313
1047
  return values.sort((a, b) => {
1314
- let aVal = state.legend.cateogryValuesOrder.indexOf(a)
1315
- let bVal = state.legend.cateogryValuesOrder.indexOf(b)
1048
+ let aVal = config.legend.cateogryValuesOrder.indexOf(a)
1049
+ let bVal = config.legend.cateogryValuesOrder.indexOf(b)
1316
1050
  if (aVal === bVal) return 0
1317
1051
  if (aVal === -1) return 1
1318
1052
  if (bVal === -1) return -1
@@ -1345,7 +1079,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1345
1079
  ))
1346
1080
  }
1347
1081
 
1348
- const isLoadedFromUrl = state?.dataKey?.includes('http://') || state?.dataKey?.includes('https://')
1082
+ const isLoadedFromUrl = config?.dataKey?.includes('http://') || config?.dataKey?.includes('https://')
1349
1083
 
1350
1084
  return (
1351
1085
  <ErrorBoundary component='EditorPanel'>
@@ -1370,9 +1104,8 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1370
1104
  </span>
1371
1105
  <ul className='geo-buttons d-grid' style={{ gridTemplateColumns: 'repeat(2, 1fr)', gap: '8px' }}>
1372
1106
  <button
1373
- className={`${
1374
- state.general.geoType === 'us' || state.general.geoType === 'us-county' ? 'active' : ''
1375
- } full-width`}
1107
+ className={`${config.general.geoType === 'us' || config.general.geoType === 'us-county' ? 'active' : ''
1108
+ } full-width`}
1376
1109
  onClick={e => {
1377
1110
  e.preventDefault()
1378
1111
  handleEditorChanges('geoType', 'us')
@@ -1382,7 +1115,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1382
1115
  <span>United States</span>
1383
1116
  </button>
1384
1117
  <button
1385
- className={`${state.general.geoType === 'us-region' ? 'active' : ''} full-width`}
1118
+ className={`${config.general.geoType === 'us-region' ? 'active' : ''} full-width`}
1386
1119
  onClick={e => {
1387
1120
  e.preventDefault()
1388
1121
  handleEditorChanges('geoType', 'us-region')
@@ -1392,7 +1125,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1392
1125
  <span>U.S. Region</span>
1393
1126
  </button>
1394
1127
  <button
1395
- className={`${state.general.geoType === 'world' ? 'active' : ''} full-width`}
1128
+ className={`${config.general.geoType === 'world' ? 'active' : ''} full-width`}
1396
1129
  onClick={e => {
1397
1130
  e.preventDefault()
1398
1131
  handleEditorChanges('geoType', 'world')
@@ -1402,7 +1135,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1402
1135
  <span>World</span>
1403
1136
  </button>
1404
1137
  <button
1405
- className={`${state.general.geoType === 'single-state' ? 'active' : ''} full-width`}
1138
+ className={`${config.general.geoType === 'single-state' ? 'active' : ''} full-width`}
1406
1139
  onClick={e => {
1407
1140
  e.preventDefault()
1408
1141
  handleEditorChanges('geoType', 'single-state')
@@ -1414,10 +1147,10 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1414
1147
  </ul>
1415
1148
  </label>
1416
1149
  {/* Select > State or County Map */}
1417
- {(state.general.geoType === 'us' || state.general.geoType === 'us-county') && (
1150
+ {(config.general.geoType === 'us' || config.general.geoType === 'us-county') && (
1418
1151
  <Select
1419
1152
  label='Geography Subtype'
1420
- value={state.general.geoType}
1153
+ value={config.general.geoType}
1421
1154
  options={[
1422
1155
  { value: 'us', label: 'US State-Level' },
1423
1156
  { value: 'us-county', label: 'US County-Level' }
@@ -1427,10 +1160,10 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1427
1160
  }}
1428
1161
  />
1429
1162
  )}
1430
- {(state.general.geoType === 'us-county' || state.general.geoType === 'single-state') && (
1163
+ {(config.general.geoType === 'us-county' || config.general.geoType === 'single-state') && (
1431
1164
  <Select
1432
1165
  label='County Census Year'
1433
- value={state.general.countyCensusYear || '2019'}
1166
+ value={config.general.countyCensusYear || '2019'}
1434
1167
  options={[
1435
1168
  { value: '2022', label: '2022' },
1436
1169
  { value: '2021', label: '2021' },
@@ -1445,50 +1178,50 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1445
1178
  }}
1446
1179
  />
1447
1180
  )}
1448
- {(state.general.geoType === 'us-county' || state.general.geoType === 'single-state') && (
1449
- <label>
1450
- <span className='edit-label column-heading'>Filter Controlling County Census Year</span>
1451
- <select
1452
- value={state.general.filterControlsCountyYear || ''}
1453
- onChange={event => {
1454
- handleEditorChanges('filterControlsCountyYear', event.target.value)
1455
- }}
1456
- >
1457
- <option value=''>None</option>
1458
- {state.filters && state.filters.map(filter => <option>{filter.columnName}</option>)}
1459
- </select>
1460
- </label>
1181
+ {(config.general.geoType === 'us-county' || config.general.geoType === 'single-state') && (
1182
+ <Select
1183
+ label='Filter Controlling County Census Year'
1184
+ value={config.general.filterControlsCountyYear || ''}
1185
+ options={[
1186
+ { value: '', label: 'None' },
1187
+ ...(config.filters
1188
+ ? config.filters.map(filter => ({ value: filter.columnName, label: filter.columnName }))
1189
+ : [])
1190
+ ]}
1191
+ onChange={event => {
1192
+ handleEditorChanges('filterControlsCountyYear', event.target.value)
1193
+ }}
1194
+ />
1461
1195
  )}
1462
1196
 
1463
- {state.general.geoType === 'single-state' && runtimeData && (
1464
- <label>
1465
- <span className='edit-label column-heading'>Filter Controlling State Picked</span>
1466
- <select
1467
- value={state.general.filterControlsStatePicked || ''}
1468
- onChange={event => {
1469
- handleEditorChanges('filterControlsStatePicked', event.target.value)
1470
- }}
1471
- >
1472
- <option value=''>None</option>
1473
- {runtimeData && columnsInData?.map(col => <option>{col}</option>)}
1474
- </select>
1475
- </label>
1197
+ {config.general.geoType === 'single-state' && runtimeData && (
1198
+ <Select
1199
+ label='Filter Controlling State Picked'
1200
+ value={config.general.filterControlsStatePicked || ''}
1201
+ options={[
1202
+ { value: '', label: 'None' },
1203
+ ...(runtimeData && columnsInData?.map(col => ({ value: col, label: col })))
1204
+ ]}
1205
+ onChange={event => {
1206
+ handleEditorChanges('filterControlsStatePicked', event.target.value)
1207
+ }}
1208
+ />
1476
1209
  )}
1477
1210
 
1478
1211
  {/* Type */}
1479
1212
  {/* Select > Filter a state */}
1480
- {state.general.geoType === 'single-state' && (
1481
- <label>
1482
- <span className='edit-label column-heading'>State Selector</span>
1483
- <select
1484
- value={state.general.statePicked.stateName}
1485
- onChange={event => {
1486
- handleEditorChanges('chooseState', event.target.value)
1487
- }}
1488
- >
1489
- <StateOptionList />
1490
- </select>
1491
- </label>
1213
+ {config.general.geoType === 'single-state' && (
1214
+ <Select
1215
+ label='State Selector'
1216
+ value={config.general.statePicked?.stateName || ''}
1217
+ options={StateOptionList().map(option => ({
1218
+ value: option.props.value,
1219
+ label: option.props.children
1220
+ }))}
1221
+ onChange={event => {
1222
+ handleEditorChanges('chooseState', event.target.value)
1223
+ }}
1224
+ />
1492
1225
  )}
1493
1226
  {/* Type */}
1494
1227
  <Select
@@ -1508,13 +1241,13 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1508
1241
  </Tooltip>
1509
1242
  </>
1510
1243
  }
1511
- value={state.general.type}
1244
+ value={config.general.type}
1512
1245
  options={[
1513
1246
  { value: 'data', label: 'Data' },
1514
- ...(state.general.geoType === 'us-county' ? [{ value: 'us-geocode', label: 'Geocode' }] : []),
1515
- ...(state.general.geoType === 'world' ? [{ value: 'world-geocode', label: 'Geocode' }] : []),
1516
- ...(state.general.geoType !== 'us-county' ? [{ value: 'navigation', label: 'Navigation' }] : []),
1517
- ...(state.general.geoType === 'world' || state.general.geoType === 'us'
1247
+ ...(config.general.geoType === 'us-county' ? [{ value: 'us-geocode', label: 'Geocode' }] : []),
1248
+ ...(config.general.geoType === 'world' ? [{ value: 'world-geocode', label: 'Geocode' }] : []),
1249
+ ...(config.general.geoType !== 'us-county' ? [{ value: 'navigation', label: 'Navigation' }] : []),
1250
+ ...(config.general.geoType === 'world' || config.general.geoType === 'us'
1518
1251
  ? [{ value: 'bubble', label: 'Bubble' }]
1519
1252
  : [])
1520
1253
  ]}
@@ -1524,16 +1257,18 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1524
1257
  />
1525
1258
 
1526
1259
  {/* Navigation Behavior */}
1527
- {(state.general.type === 'navigation' || state.general.type === 'data') && (
1260
+ {(config.general.type === 'navigation' || config.general.type === 'data') && (
1528
1261
  <Select
1529
1262
  label='Navigation Behavior'
1530
- value={state.general.navigationTarget}
1263
+ value={config.general.navigationTarget}
1531
1264
  options={[
1532
1265
  { value: '_self', label: 'Same Window' },
1533
1266
  { value: '_blank', label: 'New Window' }
1534
1267
  ]}
1535
1268
  onChange={event => {
1536
- handleEditorChanges('navigationTarget', event.target.value)
1269
+ const _newConfig = _.cloneDeep(config)
1270
+ _newConfig.general.navigationTarget = event.target.value
1271
+ setConfig(_newConfig)
1537
1272
  }}
1538
1273
  />
1539
1274
  )}
@@ -1545,7 +1280,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1545
1280
  type='radio'
1546
1281
  name='equalnumber'
1547
1282
  value='equalnumber'
1548
- checked={state.legend.type === 'equalnumber' || state.legend.type === 'equalinterval'}
1283
+ checked={config.legend.type === 'equalnumber' || config.legend.type === 'equalinterval'}
1549
1284
  onChange={e => handleEditorChanges('classificationType', e.target.value)}
1550
1285
  />
1551
1286
  Numeric/Quantitative
@@ -1555,7 +1290,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1555
1290
  type='radio'
1556
1291
  name='category'
1557
1292
  value='category'
1558
- checked={state.legend.type === 'category'}
1293
+ checked={config.legend.type === 'category'}
1559
1294
  onChange={e => handleEditorChanges('classificationType', e.target.value)}
1560
1295
  />
1561
1296
  Categorical
@@ -1563,16 +1298,47 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1563
1298
  </div>
1564
1299
  </label>
1565
1300
 
1566
- <HexSetting.DisplayAsHexMap state={state} setState={setState} handleEditorChanges={handleEditorChanges} />
1567
- <HexSetting.DisplayShapesOnHex state={state} setState={setState} />
1568
- <HexSetting.ShapeColumns state={state} setState={setState} columnsOptions={columnsOptions} />
1301
+ {/* Display as Hex */}
1302
+ {general.geoType === 'us' && general.type !== 'navigation' && general.type !== 'bubble' && (
1303
+ <label className='checkbox mt-4'>
1304
+ <input
1305
+ type='checkbox'
1306
+ checked={config.general.displayAsHex}
1307
+ onChange={event => {
1308
+ const _newConfig = _.cloneDeep(config)
1309
+ _newConfig.general.displayAsHex = event.target.checked
1310
+ setConfig(_newConfig)
1311
+ }}
1312
+ />
1313
+ <span className='edit-label'>Display As Hex Map</span>
1314
+ </label>
1315
+ )}
1316
+
1317
+ {/* Shapes on Hex */}
1318
+ <label className='checkbox mt-4'>
1319
+ <input
1320
+ type='checkbox'
1321
+ checked={config.hexMap.type === 'shapes'}
1322
+ onChange={event => {
1323
+ setConfig({
1324
+ ...config,
1325
+ hexMap: {
1326
+ ...config.hexMap,
1327
+ type: event.target.checked ? 'shapes' : 'standard'
1328
+ }
1329
+ })
1330
+ }}
1331
+ />
1332
+ <span className='edit-label'>Display Shapes on Hex Map</span>
1333
+ </label>
1334
+ <HexSetting.ShapeColumns columnsOptions={columnsOptions} />
1569
1335
 
1570
- {'us' === state.general.geoType &&
1571
- 'bubble' !== state.general.type &&
1572
- false === state.general.displayAsHex && (
1336
+ {'us' === config.general.geoType &&
1337
+ 'bubble' !== config.general.type &&
1338
+ false === config.general.displayAsHex && (
1573
1339
  <CheckBox
1574
1340
  label='Show state labels'
1575
- checked={state.general.displayStateLabels}
1341
+ checked={config.general.displayStateLabels}
1576
1342
  onChange={event => {
1577
1343
  handleEditorChanges('displayStateLabels', event.target.checked)
1578
1344
  }}
@@ -1589,13 +1355,15 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1589
1355
  />
1590
1356
  )}
1591
1357
 
1592
- {'us' === state.general.geoType && (
1358
+ {'us' === config.general.geoType && (
1593
1359
  <label className='checkbox'>
1594
1360
  <input
1595
1361
  type='checkbox'
1596
1362
  checked={general.territoriesAlwaysShow || false}
1597
1363
  onChange={event => {
1598
- handleEditorChanges('territoriesAlwaysShow', event.target.checked)
1364
+ const _newConfig = _.cloneDeep(config)
1365
+ _newConfig.general.territoriesAlwaysShow = event.target.checked
1366
+ setConfig(_newConfig)
1599
1367
  }}
1600
1368
  />
1601
1369
  <span className='edit-label'>Show All Territories</span>
@@ -1635,9 +1403,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1635
1403
  <label className='checkbox'>
1636
1404
  <input
1637
1405
  type='checkbox'
1638
- checked={state.general.showTitle || false}
1406
+ checked={config.general.showTitle || false}
1639
1407
  onChange={event => {
1640
- handleEditorChanges('showTitle', event.target.checked)
1408
+ const _newConfig = _.cloneDeep(config)
1409
+ _newConfig.general.showTitle = event.target.checked
1410
+ setConfig(_newConfig)
1641
1411
  }}
1642
1412
  />
1643
1413
  <span className='edit-label'>Show Title</span>
@@ -1747,23 +1517,24 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1747
1517
  </Tooltip>
1748
1518
  </span>
1749
1519
  <Select
1750
- value={state.columns.geo ? state.columns.geo.name : columnsOptions[0]}
1520
+ value={config.columns.geo ? config.columns.geo.name : columnsOptions[0]}
1751
1521
  options={columnsOptions.map(c => c.key)}
1752
1522
  onChange={event => {
1753
1523
  editColumn('geo', 'name', event.target.value)
1524
+ checkConfigurationNeeded(config)
1754
1525
  }}
1755
1526
  />
1756
1527
  </label>
1757
- {state.general.type === 'us-geocode' && (
1528
+ {config.general.type === 'us-geocode' && (
1758
1529
  <label className='checkbox'>
1759
1530
  <input
1760
1531
  type='checkbox'
1761
- checked={state.general.convertFipsCodes}
1532
+ checked={config.general.convertFipsCodes}
1762
1533
  onChange={event => {
1763
- setState({
1764
- ...state,
1534
+ setConfig({
1535
+ ...config,
1765
1536
  general: {
1766
- ...state.general,
1537
+ ...config.general,
1767
1538
  convertFipsCodes: event.target.checked
1768
1539
  }
1769
1540
  })
@@ -1776,15 +1547,17 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1776
1547
  <label className='checkbox'>
1777
1548
  <input
1778
1549
  type='checkbox'
1779
- checked={state.general.hideGeoColumnInTooltip || false}
1550
+ checked={config.general.hideGeoColumnInTooltip || false}
1780
1551
  onChange={event => {
1781
- handleEditorChanges('hideGeoColumnInTooltip', event.target.checked)
1552
+ const _newConfig = _.cloneDeep(config)
1553
+ _newConfig.general.hideGeoColumnInTooltip = event.target.checked
1554
+ setConfig(_newConfig)
1782
1555
  }}
1783
1556
  />
1784
1557
  <span className='edit-label'>Hide Geography Column Name in Tooltip</span>
1785
1558
  </label>
1786
1559
  <TextField
1787
- value={state.general.geoLabelOverride}
1560
+ value={config.general.geoLabelOverride}
1788
1561
  section='general'
1789
1562
  fieldName='geoLabelOverride'
1790
1563
  label='Geography Label'
@@ -1802,17 +1575,18 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1802
1575
  }
1803
1576
  />
1804
1577
  </fieldset>
1805
- {'navigation' !== state.general.type && (
1578
+ {'navigation' !== config.general.type && (
1806
1579
  <fieldset className='primary-fieldset edit-block'>
1807
1580
  <Select
1808
1581
  label='Data Column'
1809
1582
  value={columns.primary.name}
1810
1583
  options={columnsOptions.map(c => c.key)}
1811
1584
  onChange={event => {
1812
- const _state = _.cloneDeep(state)
1585
+ const _state = _.cloneDeep(config)
1813
1586
  _state.columns.primary.name = event.target.value
1814
1587
  _state.columns.primary.label = event.target.value
1815
- setState(_state)
1588
+ setConfig(_state)
1589
+ checkConfigurationNeeded(_state)
1816
1590
  }}
1817
1591
  tooltip={
1818
1592
  <Tooltip style={{ textTransform: 'none' }}>
@@ -1828,7 +1602,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1828
1602
  <label className='checkbox'>
1829
1603
  <input
1830
1604
  type='checkbox'
1831
- checked={state.general.hidePrimaryColumnInTooltip || false}
1605
+ checked={config.general.hidePrimaryColumnInTooltip || false}
1832
1606
  onChange={event => {
1833
1607
  handleEditorChanges('hidePrimaryColumnInTooltip', event.target.checked)
1834
1608
  }}
@@ -1886,7 +1660,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1886
1660
  <label className='checkbox'>
1887
1661
  <input
1888
1662
  type='checkbox'
1889
- checked={state.columns.primary.useCommas}
1663
+ checked={config.columns.primary.useCommas}
1890
1664
  onChange={event => {
1891
1665
  editColumn('primary', 'useCommas', event.target.checked)
1892
1666
  }}
@@ -1898,7 +1672,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1898
1672
  <label className='checkbox'>
1899
1673
  <input
1900
1674
  type='checkbox'
1901
- checked={state.columns.primary.dataTable || false}
1675
+ checked={config.columns.primary.dataTable || false}
1902
1676
  onChange={event => {
1903
1677
  editColumn('primary', 'dataTable', event.target.checked)
1904
1678
  }}
@@ -1910,7 +1684,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1910
1684
  <label className='checkbox'>
1911
1685
  <input
1912
1686
  type='checkbox'
1913
- checked={state.columns.primary.tooltip || false}
1687
+ checked={config.columns.primary.tooltip || false}
1914
1688
  onChange={event => {
1915
1689
  editColumn('primary', 'tooltip', event.target.checked)
1916
1690
  }}
@@ -1922,7 +1696,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1922
1696
  </fieldset>
1923
1697
  )}
1924
1698
 
1925
- {state.general.type === 'bubble' && state.legend.type === 'category' && (
1699
+ {config.general.type === 'bubble' && config.legend.type === 'category' && (
1926
1700
  <fieldset className='primary-fieldset edit-block'>
1927
1701
  <label>
1928
1702
  <span className='edit-label column-heading'>
@@ -1937,7 +1711,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1937
1711
  </Tooltip>
1938
1712
  </span>
1939
1713
  <select
1940
- value={state.columns.categorical ? state.columns.categorical.name : columnsOptions[0]}
1714
+ value={config.columns.categorical ? config.columns.categorical.name : columnsOptions[0]}
1941
1715
  onChange={event => {
1942
1716
  editColumn('categorical', 'name', event.target.value)
1943
1717
  }}
@@ -1951,7 +1725,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1951
1725
  <>
1952
1726
  <Select
1953
1727
  label='Latitude Column'
1954
- value={state.columns.latitude.name}
1728
+ value={config.columns.latitude.name}
1955
1729
  options={columnsOptions.map(c => c.key)}
1956
1730
  onChange={e => {
1957
1731
  editColumn('latitude', 'name', e.target.value)
@@ -1959,7 +1733,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1959
1733
  />
1960
1734
  <Select
1961
1735
  label='Longitude Column'
1962
- value={state.columns.longitude.name}
1736
+ value={config.columns.longitude.name}
1963
1737
  options={columnsOptions.map(c => c.key)}
1964
1738
  onChange={e => {
1965
1739
  editColumn('longitude', 'name', e.target.value)
@@ -1968,7 +1742,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1968
1742
  </>
1969
1743
  }
1970
1744
 
1971
- {'navigation' !== state.general.type && (
1745
+ {'navigation' !== config.general.type && (
1972
1746
  <fieldset className='primary-fieldset edit-block'>
1973
1747
  <label>
1974
1748
  <span className='edit-label'>
@@ -1986,7 +1760,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
1986
1760
  </Tooltip>
1987
1761
  </span>
1988
1762
  </label>
1989
- {state.legend.specialClasses.length === 2 && (
1763
+ {config.legend.specialClasses.length === 2 && (
1990
1764
  <Alert
1991
1765
  type='info'
1992
1766
  message='If a third special class is needed you can apply a pattern to set it apart.'
@@ -2005,38 +1779,38 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2005
1779
  Remove
2006
1780
  </button>
2007
1781
  <p>Special Class {i + 1}</p>
2008
- <label>
2009
- <span className='edit-label column-heading'>Data Key</span>
2010
- <select
2011
- value={specialClass.key}
2012
- onChange={e => {
2013
- editColumn('primary', 'specialClassEdit', { prop: 'key', index: i, value: e.target.value })
2014
- }}
2015
- >
2016
- {columnsOptions}
2017
- </select>
2018
- </label>
2019
- <label>
2020
- <span className='edit-label column-heading'>Value</span>
2021
- <select
2022
- value={specialClass.value}
2023
- onChange={e => {
2024
- editColumn('primary', 'specialClassEdit', {
2025
- prop: 'value',
2026
- index: i,
2027
- value: e.target.value
2028
- })
2029
- }}
2030
- >
2031
- <option value=''>- Select Value -</option>
2032
- {columnsByKey[specialClass.key] &&
2033
- columnsByKey[specialClass.key]
2034
- .sort()
2035
- .map(option => (
2036
- <option key={`special-class-value-option-${i}-${option}`}>{option}</option>
2037
- ))}
2038
- </select>
2039
- </label>
1782
+ <Select
1783
+ label='Data Key'
1784
+ value={specialClass.key}
1785
+ options={columnsOptions.map(option => ({
1786
+ value: option.key,
1787
+ label: option.key
1788
+ }))}
1789
+ onChange={event => {
1790
+ editColumn('primary', 'specialClassEdit', {
1791
+ prop: 'key',
1792
+ index: i,
1793
+ value: event.target.value
1794
+ })
1795
+ }}
1796
+ />
1797
+ <Select
1798
+ label='Value'
1799
+ value={specialClass.value}
1800
+ options={[
1801
+ { value: '', label: '- Select Value -' },
1802
+ ...(columnsByKey[specialClass.key] || [])
1803
+ .sort()
1804
+ .map(option => ({ value: option, label: option }))
1805
+ ]}
1806
+ onChange={event => {
1807
+ editColumn('primary', 'specialClassEdit', {
1808
+ prop: 'value',
1809
+ index: i,
1810
+ value: event.target.value
1811
+ })
1812
+ }}
1813
+ />
2040
1814
  <label>
2041
1815
  <span className='edit-label column-heading'>Label</span>
2042
1816
  <input
@@ -2053,7 +1827,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2053
1827
  </label>
2054
1828
  </div>
2055
1829
  ))}
2056
- {state.legend.specialClasses.length < 2 && (
1830
+ {config.legend.specialClasses.length < 2 && (
2057
1831
  <button
2058
1832
  className='btn btn-primary full-width'
2059
1833
  onClick={e => {
@@ -2083,14 +1857,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2083
1857
  </Tooltip>
2084
1858
  </span>
2085
1859
  <Select
2086
- value={state.columns.navigate ? state.columns.navigate.name : ''}
1860
+ value={config.columns.navigate ? config.columns.navigate.name : ''}
2087
1861
  options={columnsOptions.map(c => c.key)}
2088
1862
  onChange={event => {
2089
1863
  editColumn('navigate', 'name', event.target.value)
2090
1864
  }}
2091
1865
  />
2092
1866
  </label>
2093
- {'navigation' !== state.general.type && (
1867
+ {'navigation' !== config.general.type && (
2094
1868
  <fieldset className='primary-fieldset edit-block'>
2095
1869
  <label>
2096
1870
  <span className='edit-label'>
@@ -2119,17 +1893,17 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2119
1893
  >
2120
1894
  Remove
2121
1895
  </button>
2122
- <label>
2123
- <span className='edit-label column-heading'>Column</span>
2124
- <select
2125
- value={state.columns[val] ? state.columns[val].name : columnsOptions[0]}
2126
- onChange={event => {
2127
- editColumn(val, 'name', event.target.value)
2128
- }}
2129
- >
2130
- {columnsOptions}
2131
- </select>
2132
- </label>
1896
+ <Select
1897
+ label='Column'
1898
+ value={config.columns[val] ? config.columns[val].name : ''}
1899
+ options={columnsOptions.map(option => ({
1900
+ value: option.props.value,
1901
+ label: option.props.children
1902
+ }))}
1903
+ onChange={event => {
1904
+ editColumn(val, 'name', event.target.value)
1905
+ }}
1906
+ />
2133
1907
  <TextField
2134
1908
  value={columns[val].label}
2135
1909
  section='columns'
@@ -2170,7 +1944,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2170
1944
  <label className='checkbox'>
2171
1945
  <input
2172
1946
  type='checkbox'
2173
- checked={state.columns[val].useCommas}
1947
+ checked={config.columns[val].useCommas}
2174
1948
  onChange={event => {
2175
1949
  editColumn(val, 'useCommas', event.target.checked)
2176
1950
  }}
@@ -2182,7 +1956,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2182
1956
  <label className='checkbox'>
2183
1957
  <input
2184
1958
  type='checkbox'
2185
- checked={state.columns[val].dataTable}
1959
+ checked={config.columns[val].dataTable}
2186
1960
  onChange={event => {
2187
1961
  editColumn(val, 'dataTable', event.target.checked)
2188
1962
  }}
@@ -2194,7 +1968,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2194
1968
  <label className='checkbox'>
2195
1969
  <input
2196
1970
  type='checkbox'
2197
- checked={state.columns[val].tooltip}
1971
+ checked={config.columns[val].tooltip}
2198
1972
  onChange={event => {
2199
1973
  editColumn(val, 'tooltip', event.target.checked)
2200
1974
  }}
@@ -2216,7 +1990,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2216
1990
  </button>
2217
1991
  </fieldset>
2218
1992
  )}
2219
- {'category' === state.legend.type && (
1993
+ {'category' === config.legend.type && (
2220
1994
  <fieldset className='primary-fieldset edit-block'>
2221
1995
  <label>
2222
1996
  <span className='edit-label'>
@@ -2231,14 +2005,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2231
2005
  </Tooltip>
2232
2006
  </span>
2233
2007
  </label>
2234
- {state.legend.additionalCategories &&
2235
- state.legend.additionalCategories.map((val, i) => (
2008
+ {config.legend.additionalCategories &&
2009
+ config.legend.additionalCategories.map((val, i) => (
2236
2010
  <fieldset className='edit-block' key={val}>
2237
2011
  <button
2238
2012
  className='remove-column'
2239
2013
  onClick={event => {
2240
2014
  event.preventDefault()
2241
- const updatedAdditionaCategories = [...state.legend.additionalCategories]
2015
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
2242
2016
  updatedAdditionaCategories.splice(i, 1)
2243
2017
  updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2244
2018
  }}
@@ -2253,7 +2027,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2253
2027
  subsection={null}
2254
2028
  fieldName='additionalCategories'
2255
2029
  updateField={(section, subsection, fieldName, value) => {
2256
- const updatedAdditionaCategories = [...state.legend.additionalCategories]
2030
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
2257
2031
  updatedAdditionaCategories[i] = value
2258
2032
  updateField(section, subsection, fieldName, updatedAdditionaCategories)
2259
2033
  }}
@@ -2265,7 +2039,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2265
2039
  className={'btn btn-primary full-width'}
2266
2040
  onClick={event => {
2267
2041
  event.preventDefault()
2268
- const updatedAdditionaCategories = [...(state.legend.additionalCategories || [])]
2042
+ const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
2269
2043
  updatedAdditionaCategories.push('')
2270
2044
  updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2271
2045
  }}
@@ -2277,7 +2051,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2277
2051
  </AccordionItemPanel>
2278
2052
  </AccordionItem>{' '}
2279
2053
  {/* Columns */}
2280
- {'navigation' !== state.general.type && (
2054
+ {'navigation' !== config.general.type && (
2281
2055
  <AccordionItem>
2282
2056
  {' '}
2283
2057
  {/* Legend */}
@@ -2285,7 +2059,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2285
2059
  <AccordionItemButton>Legend</AccordionItemButton>
2286
2060
  </AccordionItemHeading>
2287
2061
  <AccordionItemPanel>
2288
- {(state.legend.type === 'equalnumber' || state.legend.type === 'equalinterval') && (
2062
+ {(config.legend.type === 'equalnumber' || config.legend.type === 'equalinterval') && (
2289
2063
  <Select
2290
2064
  label='Legend Type'
2291
2065
  value={legend.type}
@@ -2294,23 +2068,46 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2294
2068
  { value: 'equalinterval', label: 'Equal Interval' }
2295
2069
  ]}
2296
2070
  onChange={event => {
2297
- handleEditorChanges('legendType', event.target.value)
2071
+ let testForType = Number(typeof config.data[0][config.columns.primary.name])
2072
+ let hasValue = config.data[0][config.columns.primary.name]
2073
+ let messages = []
2074
+
2075
+ if (!hasValue) {
2076
+ messages.push(
2077
+ `There appears to be values missing for data in the primary column ${config.columns.primary.name}`
2078
+ )
2079
+ }
2080
+
2081
+ if (testForType === 'string' && isNaN(testForType) && value !== 'category') {
2082
+ messages.push(
2083
+ 'Error with legend. Primary columns that are text must use a categorical legend type. Try changing the legend type to DEV-12345categorical.'
2084
+ )
2085
+ } else {
2086
+ messages = []
2087
+ }
2088
+
2089
+ const _newConfig = _.cloneDeep(config)
2090
+ _newConfig.legend.type = event.target.value
2091
+ _newConfig.runtime.editorErrorMessage = messages
2092
+ setConfig(_newConfig)
2298
2093
  }}
2299
2094
  />
2300
2095
  )}
2301
- {'navigation' !== state.general.type && (
2096
+ {'navigation' !== config.general.type && (
2302
2097
  <label className='checkbox'>
2303
2098
  <input
2304
2099
  type='checkbox'
2305
- checked={state.general.showSidebar || false}
2100
+ checked={config.general.showSidebar || false}
2306
2101
  onChange={event => {
2307
- handleEditorChanges('showSidebar', event.target.checked)
2102
+ const _newConfig = _.cloneDeep(config)
2103
+ _newConfig.general.showSidebar = event.target.checked
2104
+ setConfig(_newConfig)
2308
2105
  }}
2309
2106
  />
2310
2107
  <span className='edit-label'>Show Legend</span>
2311
2108
  </label>
2312
2109
  )}
2313
- {'navigation' !== state.general.type && (
2110
+ {'navigation' !== config.general.type && (
2314
2111
  <>
2315
2112
  <Select
2316
2113
  label='Legend Position'
@@ -2324,15 +2121,15 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2324
2121
  handleEditorChanges('sidebarPosition', event.target.value)
2325
2122
  }}
2326
2123
  />
2327
- {(state.legend.position === 'side' || !state.legend.position) &&
2328
- state.legend.style === 'gradient' && (
2124
+ {(config.legend.position === 'side' || !config.legend.position) &&
2125
+ config.legend.style === 'gradient' && (
2329
2126
  <span style={{ color: 'red', fontSize: '14px' }}>
2330
2127
  Position must be set to top or bottom to use gradient style.
2331
2128
  </span>
2332
2129
  )}
2333
2130
  </>
2334
2131
  )}
2335
- {'navigation' !== state.general.type && (
2132
+ {'navigation' !== config.general.type && (
2336
2133
  <Select
2337
2134
  label={
2338
2135
  <>
@@ -2364,7 +2161,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2364
2161
  }}
2365
2162
  />
2366
2163
  )}
2367
- {'navigation' !== state.general.type && state.legend.style === 'gradient' && (
2164
+ {'navigation' !== config.general.type && config.legend.style === 'gradient' && (
2368
2165
  <label>
2369
2166
  <span className='edit-label'>Gradient Style</span>
2370
2167
  <select
@@ -2378,7 +2175,29 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2378
2175
  </select>
2379
2176
  </label>
2380
2177
  )}
2381
- {'navigation' !== state.general.type && state.legend.style === 'gradient' && (
2178
+ {allowLegendSeparators && (
2179
+ <TextField
2180
+ value={legend.separators}
2181
+ updateField={updateField}
2182
+ section='legend'
2183
+ fieldName='separators'
2184
+ label='Legend Separators'
2185
+ placeholder='ex: 1,4'
2186
+ tooltip={
2187
+ <Tooltip style={{ textTransform: 'none' }}>
2188
+ <Tooltip.Target>
2189
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2190
+ </Tooltip.Target>
2191
+ <Tooltip.Content>
2192
+ <p>
2193
+ Separators between legend items represented by the legend item numbers separated by commas.
2194
+ </p>
2195
+ </Tooltip.Content>
2196
+ </Tooltip>
2197
+ }
2198
+ />
2199
+ )}
2200
+ {'navigation' !== config.general.type && config.legend.style === 'gradient' && (
2382
2201
  <label>
2383
2202
  <span className='edit-label'>Tick Rotation (Degrees)</span>
2384
2203
  <input
@@ -2420,7 +2239,12 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2420
2239
  type='checkbox'
2421
2240
  checked={legend.singleColumn}
2422
2241
  onChange={event => {
2423
- handleEditorChanges('singleColumnLegend', event.target.checked)
2242
+ const _newConfig = _.cloneDeep(config)
2243
+ _newConfig.legend.singleColumn = event.target.checked
2244
+ _newConfig.legend.singleRow = false
2245
+ _newConfig.legend.verticalSorted = false
2246
+
2247
+ setConfig(_newConfig)
2424
2248
  }}
2425
2249
  />
2426
2250
  <span className='edit-label'>Single Column Legend</span>
@@ -2432,19 +2256,39 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2432
2256
  type='checkbox'
2433
2257
  checked={legend.singleRow}
2434
2258
  onChange={event => {
2435
- handleEditorChanges('singleRowLegend', event.target.checked)
2259
+ const _newConfig = _.cloneDeep(config)
2260
+ _newConfig.legend.singleRow = event.target.checked
2261
+ _newConfig.legend.singleColumn = false
2262
+ _newConfig.legend.verticalSorted = false
2263
+
2264
+ setConfig(_newConfig)
2436
2265
  }}
2437
2266
  />
2438
2267
  <span className='edit-label'>Single Row Legend</span>
2439
2268
  </label>
2440
2269
  )}
2441
- {state.legend.style !== 'gradient' && (
2270
+
2271
+ {'navigation' !== config.general.type && config.legend.type === 'category' && (
2272
+ <Select
2273
+ label='Legend Group By :'
2274
+ value={legend.groupBy || ''}
2275
+ options={columnsOptions.map(c => c.key)}
2276
+ onChange={event => {
2277
+ const _newConfig = _.cloneDeep(config)
2278
+ _newConfig.legend.groupBy = event.target.value
2279
+ setConfig(_newConfig)
2280
+ }}
2281
+ />
2282
+ )}
2283
+ {config.legend.style !== 'gradient' && (
2442
2284
  <label className='checkbox'>
2443
2285
  <input
2444
2286
  type='checkbox'
2445
2287
  checked={legend.verticalSorted}
2446
2288
  onChange={event => {
2447
- handleEditorChanges('verticalSortedLegend', event.target.checked)
2289
+ const _newConfig = _.cloneDeep(config)
2290
+ _newConfig.legend.verticalSorted = event.target.checked
2291
+ setConfig(_newConfig)
2448
2292
  }}
2449
2293
  />
2450
2294
  <span className='edit-label'>Vertical sorted legend</span>
@@ -2469,7 +2313,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2469
2313
  <input
2470
2314
  type='checkbox'
2471
2315
  checked={legend.separateZero || false}
2472
- onChange={event => handleEditorChanges('separateZero', event.target.checked)}
2316
+ onChange={event => {
2317
+ const _newConfig = _.cloneDeep(config)
2318
+ _newConfig.legend.separateZero = event.target.checked
2319
+ return setConfig(_newConfig)
2320
+ }}
2473
2321
  />
2474
2322
  <span className='edit-label column-heading'>
2475
2323
  Separate Zero
@@ -2487,14 +2335,17 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2487
2335
  </span>
2488
2336
  </label>
2489
2337
  )}
2338
+
2490
2339
  {/* Temp Checkbox */}
2491
- {state.legend.type === 'equalnumber' && (
2340
+ {config.legend.type === 'equalnumber' && (
2492
2341
  <label className='checkbox'>
2493
2342
  <input
2494
2343
  type='checkbox'
2495
- checked={state.general.equalNumberOptIn}
2344
+ checked={config.general.equalNumberOptIn}
2496
2345
  onChange={event => {
2497
- handleEditorChanges('showEqualNumber', event.target.checked)
2346
+ const _newConfig = _.clone(config)
2347
+ _newConfig.general.equalNumberOptIn = event.target.checked
2348
+ setConfig(_newConfig)
2498
2349
  }}
2499
2350
  />
2500
2351
  <span className='edit-label column-heading'>Use new quantile legend</span>
@@ -2511,6 +2362,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2511
2362
  </Tooltip>
2512
2363
  </label>
2513
2364
  )}
2365
+
2514
2366
  {'category' !== legend.type && (
2515
2367
  <Select
2516
2368
  label={
@@ -2606,24 +2458,21 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2606
2458
  <DynamicDesc value={legend.descriptions[String(activeFilterValueForDescription)]} />
2607
2459
  </label>
2608
2460
  <label>
2609
- <select
2461
+ <Select
2462
+ label='Filter Value'
2610
2463
  value={String(activeFilterValueForDescription)}
2464
+ options={filterValueOptionList.map(arr => ({
2465
+ value: arr,
2466
+ label: displayFilterLegendValue(arr)
2467
+ }))}
2611
2468
  onChange={event => {
2612
2469
  handleEditorChanges('changeActiveFilterValue', event.target.value)
2613
2470
  }}
2614
- >
2615
- {filterValueOptionList.map((arr, i) => {
2616
- return (
2617
- <option value={arr} key={i}>
2618
- {displayFilterLegendValue(arr)}
2619
- </option>
2620
- )
2621
- })}
2622
- </select>
2471
+ />
2623
2472
  </label>
2624
2473
  </React.Fragment>
2625
2474
  )}
2626
- {state.filters.length > 0 && (
2475
+ {config.filters.length > 0 && (
2627
2476
  <label className='checkbox'>
2628
2477
  <input
2629
2478
  type='checkbox'
@@ -2651,7 +2500,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2651
2500
  </span>
2652
2501
  </label>
2653
2502
  )}
2654
- {(state.filters.length > 0 || state.general.type === 'bubble' || state.general.geoType === 'us') && (
2503
+ {(config.filters.length > 0 || config.general.type === 'bubble' || config.general.geoType === 'us') && (
2655
2504
  <label className='checkbox'>
2656
2505
  <input
2657
2506
  type='checkbox'
@@ -2680,19 +2529,33 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2680
2529
  </AccordionItemPanel>
2681
2530
  </AccordionItem>
2682
2531
  )}
2683
- {'navigation' !== state.general.type && (
2684
- <AccordionItem>
2685
- {' '}
2686
- {/* Filters */}
2687
- <AccordionItemHeading>
2688
- <AccordionItemButton>Filters</AccordionItemButton>
2689
- </AccordionItemHeading>
2690
- <AccordionItemPanel>
2691
- <VizFilterEditor config={state} updateField={updateField} rawData={state.data} />
2692
- </AccordionItemPanel>
2693
- </AccordionItem>
2532
+ {'navigation' !== config.general.type && (
2533
+ <>
2534
+ <AccordionItem>
2535
+ {/* Filters */}
2536
+ <AccordionItemHeading>
2537
+ <AccordionItemButton>Filters</AccordionItemButton>
2538
+ </AccordionItemHeading>
2539
+ <AccordionItemPanel>
2540
+ <VizFilterEditor
2541
+ config={config}
2542
+ updateField={updateField}
2543
+ rawData={config.data}
2544
+ hasFootnotes={isDashboard}
2545
+ />
2546
+ </AccordionItemPanel>
2547
+ </AccordionItem>
2548
+ <AccordionItem>
2549
+ <AccordionItemHeading>
2550
+ <AccordionItemButton>Footnotes</AccordionItemButton>
2551
+ </AccordionItemHeading>
2552
+ <AccordionItemPanel>
2553
+ <FootnotesEditor config={config} updateField={updateField} datasets={datasets} />
2554
+ </AccordionItemPanel>
2555
+ </AccordionItem>
2556
+ </>
2694
2557
  )}
2695
- {'navigation' !== state.general.type && (
2558
+ {'navigation' !== config.general.type && (
2696
2559
  <AccordionItem>
2697
2560
  {' '}
2698
2561
  {/* Data Table */}
@@ -2722,12 +2585,12 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2722
2585
  <label className='checkbox'>
2723
2586
  <input
2724
2587
  type='checkbox'
2725
- checked={state.table.wrapColumns}
2588
+ checked={config.table.wrapColumns}
2726
2589
  onChange={event => {
2727
- setState({
2728
- ...state,
2590
+ setConfig({
2591
+ ...config,
2729
2592
  table: {
2730
- ...state.table,
2593
+ ...config.table,
2731
2594
  wrapColumns: event.target.checked
2732
2595
  }
2733
2596
  })
@@ -2738,7 +2601,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2738
2601
  <label className='checkbox'>
2739
2602
  <input
2740
2603
  type='checkbox'
2741
- checked={state.table.forceDisplay !== undefined ? state.table.forceDisplay : !isDashboard}
2604
+ checked={config.table.forceDisplay !== undefined ? config.table.forceDisplay : !isDashboard}
2742
2605
  onChange={event => {
2743
2606
  handleEditorChanges('showDataTable', event.target.checked)
2744
2607
  }}
@@ -2761,6 +2624,35 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2761
2624
  </Tooltip>
2762
2625
  </span>
2763
2626
  </label>
2627
+ <label className='checkbox'>
2628
+ <input
2629
+ type='checkbox'
2630
+ checked={config.table.showNonGeoData}
2631
+ onChange={event => {
2632
+ setConfig({
2633
+ ...config,
2634
+ table: {
2635
+ ...config.table,
2636
+ showNonGeoData: event.target.checked
2637
+ }
2638
+ })
2639
+ }}
2640
+ />
2641
+ <span className='edit-label column-heading'>
2642
+ Show Non Geographic Data
2643
+ <Tooltip style={{ textTransform: 'none' }}>
2644
+ <Tooltip.Target>
2645
+ <Icon
2646
+ display='question'
2647
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2648
+ />
2649
+ </Tooltip.Target>
2650
+ <Tooltip.Content>
2651
+ <p>Show any data not associated with a geographic location</p>
2652
+ </Tooltip.Content>
2653
+ </Tooltip>
2654
+ </span>
2655
+ </label>
2764
2656
  <TextField
2765
2657
  value={table.indexLabel || ''}
2766
2658
  updateField={updateField}
@@ -2783,7 +2675,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2783
2675
  }
2784
2676
  />
2785
2677
  <TextField
2786
- value={state.table.caption}
2678
+ value={config.table.caption}
2787
2679
  updateField={updateField}
2788
2680
  section='table'
2789
2681
  fieldName='caption'
@@ -2804,14 +2696,14 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2804
2696
  <label className='checkbox'>
2805
2697
  <input
2806
2698
  type='checkbox'
2807
- checked={state.table.limitHeight}
2699
+ checked={config.table.limitHeight}
2808
2700
  onChange={event => {
2809
2701
  handleEditorChanges('limitDataTableHeight', event.target.checked)
2810
2702
  }}
2811
2703
  />
2812
2704
  <span className='edit-label'>Limit Table Height</span>
2813
2705
  </label>
2814
- {state.table.limitHeight && (
2706
+ {config.table.limitHeight && (
2815
2707
  <TextField
2816
2708
  value={table.height}
2817
2709
  updateField={updateField}
@@ -2824,10 +2716,22 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2824
2716
  max='500'
2825
2717
  />
2826
2718
  )}
2719
+
2720
+ <TextField
2721
+ value={table.cellMinWidth}
2722
+ updateField={updateField}
2723
+ section='table'
2724
+ fieldName='cellMinWidth'
2725
+ label='Table Cell Min Width'
2726
+ type='number'
2727
+ min='0'
2728
+ max='500'
2729
+ />
2730
+
2827
2731
  <label className='checkbox'>
2828
2732
  <input
2829
2733
  type='checkbox'
2830
- checked={state.table.expanded || false}
2734
+ checked={config.table.expanded || false}
2831
2735
  onChange={event => {
2832
2736
  handleEditorChanges('expandDataTable', event.target.checked)
2833
2737
  }}
@@ -2835,19 +2739,19 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2835
2739
  <span className='edit-label'>Map loads with data table expanded</span>
2836
2740
  </label>
2837
2741
  <CheckBox
2838
- value={state.table.download}
2742
+ value={config.table.download}
2839
2743
  fieldName='download'
2840
2744
  label='Show Download CSV Link'
2841
2745
  section='table'
2842
2746
  updateField={updateField}
2843
2747
  />
2844
- {state.table.download && (
2748
+ {config.table.download && (
2845
2749
  <>
2846
2750
  <label className='checkbox'>
2847
2751
  <input
2848
2752
  type='checkbox'
2849
2753
  className='ms-4'
2850
- checked={state.table.showDownloadLinkBelow}
2754
+ checked={config.table.showDownloadLinkBelow}
2851
2755
  onChange={event => {
2852
2756
  handleEditorChanges('toggleDownloadLinkBelow', event.target.checked)
2853
2757
  }}
@@ -2855,7 +2759,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2855
2759
  <span className='edit-label'>Show Link Below Table</span>
2856
2760
  </label>
2857
2761
  <CheckBox
2858
- value={state.table.downloadVisibleDataOnly}
2762
+ value={config.table.downloadVisibleDataOnly}
2859
2763
  fieldName='downloadVisibleDataOnly'
2860
2764
  className='ms-4'
2861
2765
  label='Download only visible data'
@@ -2868,9 +2772,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2868
2772
  <label className='checkbox'>
2869
2773
  <input
2870
2774
  type='checkbox'
2871
- checked={state.table.showDataTableLink}
2775
+ checked={config.table.showDataTableLink}
2872
2776
  onChange={event => {
2873
- handleEditorChanges('toggleDataTableLink', event.target.checked)
2777
+ const _newConfig = _.cloneDeep(config)
2778
+ _newConfig.table.showDataTableLink = event.target.checked
2779
+ setConfig(_newConfig)
2874
2780
  }}
2875
2781
  />
2876
2782
  <span className='edit-label'>Show Data Table Name & Link</span>
@@ -2880,9 +2786,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2880
2786
  <label className='checkbox'>
2881
2787
  <input
2882
2788
  type='checkbox'
2883
- checked={state.table.showDownloadUrl}
2789
+ checked={config.table.showDownloadUrl}
2884
2790
  onChange={event => {
2885
- handleEditorChanges('toggleDataUrl', event.target.checked)
2791
+ const _newConfig = _.cloneDeep(config)
2792
+ _newConfig.table.showDownloadUrl = event.target.checked
2793
+ setConfig(_newConfig)
2886
2794
  }}
2887
2795
  />
2888
2796
  <span className='edit-label'>Show URL to Automatically Updated Data</span>
@@ -2891,7 +2799,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2891
2799
  <label className='checkbox'>
2892
2800
  <input
2893
2801
  type='checkbox'
2894
- checked={state.general.showFullGeoNameInCSV}
2802
+ checked={config.table.showFullGeoNameInCSV}
2895
2803
  onChange={event => {
2896
2804
  handleEditorChanges('toggleShowFullGeoNameInCSV', event.target.checked)
2897
2805
  }}
@@ -2901,7 +2809,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2901
2809
  <label className='checkbox'>
2902
2810
  <input
2903
2811
  type='checkbox'
2904
- checked={state.general.showDownloadImgButton}
2812
+ checked={config.general.showDownloadImgButton}
2905
2813
  onChange={event => {
2906
2814
  handleEditorChanges('toggleDownloadImgButton', event.target.checked)
2907
2815
  }}
@@ -2929,29 +2837,32 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2929
2837
  <AccordionItemButton>Interactivity</AccordionItemButton>
2930
2838
  </AccordionItemHeading>
2931
2839
  <AccordionItemPanel>
2932
- <label>
2933
- <span className='edit-label'>
2934
- Detail displays on{' '}
2935
- <Tooltip style={{ textTransform: 'none' }}>
2936
- <Tooltip.Target>
2937
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2938
- </Tooltip.Target>
2939
- <Tooltip.Content>
2940
- <p>At mobile sizes, information always appears in a popover modal when a user taps on an item.</p>
2941
- </Tooltip.Content>
2942
- </Tooltip>
2943
- </span>
2944
- <select
2945
- value={state.tooltips.appearanceType}
2946
- onChange={event => {
2947
- handleEditorChanges('appearanceType', event.target.value)
2948
- }}
2949
- >
2950
- <option value='hover'>Hover - Tooltip</option>
2951
- <option value='click'>Click - Popover Modal</option>
2952
- </select>
2953
- </label>
2954
- {'click' === state.tooltips.appearanceType && (
2840
+ <Select
2841
+ label={
2842
+ <>
2843
+ Detail displays on{' '}
2844
+ <Tooltip style={{ textTransform: 'none' }}>
2845
+ <Tooltip.Target>
2846
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2847
+ </Tooltip.Target>
2848
+ <Tooltip.Content>
2849
+ <p>
2850
+ At mobile sizes, information always appears in a popover modal when a user taps on an item.
2851
+ </p>
2852
+ </Tooltip.Content>
2853
+ </Tooltip>
2854
+ </>
2855
+ }
2856
+ value={config.tooltips.appearanceType}
2857
+ options={[
2858
+ { value: 'hover', label: 'Hover - Tooltip' },
2859
+ { value: 'click', label: 'Click - Popover Modal' }
2860
+ ]}
2861
+ onChange={event => {
2862
+ handleEditorChanges('appearanceType', event.target.value)
2863
+ }}
2864
+ />
2865
+ {'click' === config.tooltips.appearanceType && (
2955
2866
  <TextField
2956
2867
  value={tooltips.linkLabel}
2957
2868
  section='tooltips'
@@ -2963,7 +2874,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2963
2874
  <label className='checkbox'>
2964
2875
  <input
2965
2876
  type='checkbox'
2966
- checked={state.tooltips.capitalizeLabels}
2877
+ checked={config.tooltips.capitalizeLabels}
2967
2878
  onChange={event => {
2968
2879
  handleEditorChanges('capitalizeLabels', event.target.checked)
2969
2880
  }}
@@ -2982,7 +2893,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2982
2893
  <label>
2983
2894
  <span className='edit-label'>Header Theme</span>
2984
2895
  <ul className='color-palette'>
2985
- {headerColors.map(palette => {
2896
+ {HEADER_COLORS.map(palette => {
2986
2897
  return (
2987
2898
  <li
2988
2899
  title={palette}
@@ -2990,7 +2901,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2990
2901
  onClick={() => {
2991
2902
  handleEditorChanges('headerColor', palette)
2992
2903
  }}
2993
- className={state.general.headerColor === palette ? 'selected ' + palette : palette}
2904
+ className={config.general.headerColor === palette ? 'selected ' + palette : palette}
2994
2905
  ></li>
2995
2906
  )
2996
2907
  })}
@@ -2999,7 +2910,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
2999
2910
  <label className='checkbox'>
3000
2911
  <input
3001
2912
  type='checkbox'
3002
- checked={state.general.showTitle || false}
2913
+ checked={config.general.showTitle || false}
3003
2914
  onChange={event => {
3004
2915
  handleEditorChanges('showTitle', event.target.checked)
3005
2916
  }}
@@ -3007,30 +2918,31 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3007
2918
  <span className='edit-label'>Show Title</span>
3008
2919
  </label>
3009
2920
 
3010
- {'navigation' === state.general.type && (
2921
+ {'navigation' === config.general.type && (
3011
2922
  <label className='checkbox'>
3012
2923
  <input
3013
2924
  type='checkbox'
3014
- checked={state.general.fullBorder || false}
2925
+ checked={config.general.fullBorder || false}
3015
2926
  onChange={event => {
3016
- handleEditorChanges('fullBorder', event.target.checked)
2927
+ const _newConfig = _.cloneDeep(config)
2928
+ _newConfig.general.fullBorder = event.target.checked
2929
+ setConfig(_newConfig)
3017
2930
  }}
3018
2931
  />
3019
2932
  <span className='edit-label'>Add border around map</span>
3020
2933
  </label>
3021
2934
  )}
3022
- <label>
3023
- <span className='edit-label'>Geo Border Color</span>
3024
- <select
3025
- value={state.general.geoBorderColor || false}
3026
- onChange={event => {
3027
- handleEditorChanges('geoBorderColor', event.target.value)
3028
- }}
3029
- >
3030
- <option value='darkGray'>Dark Gray (Default)</option>
3031
- <option value='sameAsBackground'>White</option>
3032
- </select>
3033
- </label>
2935
+ <Select
2936
+ label='Geo Border Color'
2937
+ value={config.general.geoBorderColor || ''}
2938
+ options={[
2939
+ { value: 'darkGray', label: 'Dark Gray (Default)' },
2940
+ { value: 'sameAsBackground', label: 'White' }
2941
+ ]}
2942
+ onChange={event => {
2943
+ handleEditorChanges('geoBorderColor', event.target.value)
2944
+ }}
2945
+ />
3034
2946
  <label>
3035
2947
  <span className='edit-label'>Map Color Palette</span>
3036
2948
  </label>
@@ -3041,8 +2953,22 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3041
2953
  fieldName='isReversed'
3042
2954
  size='small'
3043
2955
  label='Use selected palette in reverse order'
3044
- updateField={updateField}
3045
- value={state.general.palette.isReversed}
2956
+ onClick={() => {
2957
+ const _state = _.cloneDeep(config)
2958
+ _state.general.palette.isReversed = !_state.general.palette.isReversed
2959
+ let paletteName = ''
2960
+ if (_state.general.palette.isReversed && !config.color.endsWith('reverse')) {
2961
+ paletteName = config.color + 'reverse'
2962
+ }
2963
+ if (!_state.general.palette.isReversed && config.color.endsWith('reverse')) {
2964
+ paletteName = config.color.slice(0, -7)
2965
+ }
2966
+ if (paletteName) {
2967
+ _state.color = paletteName
2968
+ }
2969
+ setConfig(_state)
2970
+ }}
2971
+ value={config.general.palette.isReversed}
3046
2972
  />
3047
2973
  <span>Sequential</span>
3048
2974
  <ul className='color-palette'>
@@ -3064,9 +2990,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3064
2990
  title={palette}
3065
2991
  key={palette}
3066
2992
  onClick={() => {
3067
- handleEditorChanges('color', palette)
2993
+ const _newConfig = _.cloneDeep(config)
2994
+ _newConfig.color = palette
2995
+ setConfig(_newConfig)
3068
2996
  }}
3069
- className={state.color === palette ? 'selected' : ''}
2997
+ className={config.color === palette ? 'selected' : ''}
3070
2998
  >
3071
2999
  <span style={colorOne}></span>
3072
3000
  <span style={colorTwo}></span>
@@ -3091,7 +3019,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3091
3019
  }
3092
3020
 
3093
3021
  // hide palettes with too few colors for region maps
3094
- if (colorPalettes[palette].length <= 8 && state.general.geoType === 'us-region') {
3022
+ if (colorPalettes[palette].length <= 8 && config.general.geoType === 'us-region') {
3095
3023
  return ''
3096
3024
  }
3097
3025
  return (
@@ -3099,9 +3027,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3099
3027
  title={palette}
3100
3028
  key={palette}
3101
3029
  onClick={() => {
3102
- handleEditorChanges('color', palette)
3030
+ const _newConfig = _.cloneDeep(config)
3031
+ _newConfig.color = palette
3032
+ setConfig(_newConfig)
3103
3033
  }}
3104
- className={state.color === palette ? 'selected' : ''}
3034
+ className={config.color === palette ? 'selected' : ''}
3105
3035
  >
3106
3036
  <span style={colorOne}></span>
3107
3037
  <span style={colorTwo}></span>
@@ -3126,7 +3056,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3126
3056
  }
3127
3057
 
3128
3058
  // hide palettes with too few colors for region maps
3129
- if (colorPalettes[palette].length <= 8 && state.general.geoType === 'us-region') {
3059
+ if (colorPalettes[palette].length <= 8 && config.general.geoType === 'us-region') {
3130
3060
  return ''
3131
3061
  }
3132
3062
  return (
@@ -3136,7 +3066,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3136
3066
  onClick={() => {
3137
3067
  handleEditorChanges('color', palette)
3138
3068
  }}
3139
- className={state.color === palette ? 'selected' : ''}
3069
+ className={config.color === palette ? 'selected' : ''}
3140
3070
  >
3141
3071
  <span style={colorOne}></span>
3142
3072
  <span style={colorTwo}></span>
@@ -3149,7 +3079,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3149
3079
  Geocode Settings
3150
3080
  <TextField
3151
3081
  type='number'
3152
- value={state.visual.geoCodeCircleSize}
3082
+ value={config.visual.geoCodeCircleSize}
3153
3083
  section='visual'
3154
3084
  max='10'
3155
3085
  fieldName='geoCodeCircleSize'
@@ -3158,11 +3088,11 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3158
3088
  />
3159
3089
  </label>
3160
3090
 
3161
- {state.general.type === 'bubble' && (
3091
+ {config.general.type === 'bubble' && (
3162
3092
  <>
3163
3093
  <TextField
3164
3094
  type='number'
3165
- value={state.visual.minBubbleSize}
3095
+ value={config.visual.minBubbleSize}
3166
3096
  section='visual'
3167
3097
  fieldName='minBubbleSize'
3168
3098
  label='Minimum Bubble Size'
@@ -3170,7 +3100,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3170
3100
  />
3171
3101
  <TextField
3172
3102
  type='number'
3173
- value={state.visual.maxBubbleSize}
3103
+ value={config.visual.maxBubbleSize}
3174
3104
  section='visual'
3175
3105
  fieldName='maxBubbleSize'
3176
3106
  label='Maximum Bubble Size'
@@ -3178,86 +3108,94 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3178
3108
  />
3179
3109
  </>
3180
3110
  )}
3181
- {(state.general.geoType === 'world' ||
3182
- (state.general.geoType === 'us' && state.general.type === 'bubble')) && (
3183
- <label className='checkbox'>
3184
- <input
3185
- type='checkbox'
3186
- checked={state.visual.showBubbleZeros}
3187
- onChange={event => {
3188
- handleEditorChanges('showBubbleZeros', event.target.checked)
3189
- }}
3190
- />
3191
- <span className='edit-label'>Show Data with Zero's on Bubble Map</span>
3192
- </label>
3193
- )}
3194
- {(state.general.geoType === 'world' || state.general.geoType === 'single-state') && (
3111
+ {(config.general.geoType === 'world' ||
3112
+ (config.general.geoType === 'us' && config.general.type === 'bubble')) && (
3113
+ <label className='checkbox'>
3114
+ <input
3115
+ type='checkbox'
3116
+ checked={config.visual.showBubbleZeros}
3117
+ onChange={event => {
3118
+ const _newConfig = _.cloneDeep(config)
3119
+ _newConfig.visual.showBubbleZeros = event.target.checked
3120
+ setConfig(_newConfig)
3121
+ }}
3122
+ />
3123
+ <span className='edit-label'>Show Data with Zero's on Bubble Map</span>
3124
+ </label>
3125
+ )}
3126
+ {(config.general.geoType === 'world' || config.general.geoType === 'single-state') && (
3195
3127
  <label className='checkbox'>
3196
3128
  <input
3197
3129
  type='checkbox'
3198
- checked={state.general.allowMapZoom}
3130
+ checked={config.general.allowMapZoom}
3199
3131
  onChange={event => {
3200
- handleEditorChanges('allowMapZoom', event.target.checked)
3132
+ const _newConfig = _.cloneDeep(config)
3133
+ _newConfig.general.allowMapZoom = event.target.checked
3134
+ _newConfig.mapPosition.coordinates = config.general.geoType === 'world' ? [0, 30] : [0, 0]
3135
+ _newConfig.mapPosition.zoom = 1
3136
+ setConfig(_newConfig)
3201
3137
  }}
3202
3138
  />
3203
3139
  <span className='edit-label'>Allow Map Zooming</span>
3204
3140
  </label>
3205
3141
  )}
3206
- {state.general.type === 'bubble' && (
3142
+ {config.general.type === 'bubble' && (
3207
3143
  <label className='checkbox'>
3208
3144
  <input
3209
3145
  type='checkbox'
3210
- checked={state.visual.extraBubbleBorder}
3146
+ checked={config.visual.extraBubbleBorder}
3211
3147
  onChange={event => {
3212
- handleEditorChanges('toggleExtraBubbleBorder', event.target.checked)
3148
+ const _newConfig = _.cloneDeep(config)
3149
+ _newConfig.visual.extraBubbleBorder = event.target.checked
3150
+ setConfig(_newConfig)
3213
3151
  }}
3214
3152
  />
3215
3153
  <span className='edit-label'>Bubble Map has extra border</span>
3216
3154
  </label>
3217
3155
  )}
3218
- {(state.general.geoType === 'us' ||
3219
- state.general.geoType === 'us-county' ||
3220
- state.general.geoType === 'world') && (
3221
- <>
3222
- <label>
3223
- <span className='edit-label'>Default City Style</span>
3224
- <select
3225
- value={state.visual.cityStyle || false}
3226
- onChange={event => {
3227
- handleEditorChanges('handleCityStyle', event.target.value)
3228
- }}
3229
- >
3230
- <option value='circle'>Circle</option>
3231
- <option value='pin'>Pin</option>
3232
- <option value='square'>Square</option>
3233
- <option value='triangle'>Triangle</option>
3234
- <option value='diamond'>Diamond</option>
3235
- <option value='star'>Star</option>
3236
- </select>
3237
- </label>
3238
- <TextField
3239
- value={state.visual.cityStyleLabel}
3240
- section='visual'
3241
- fieldName='cityStyleLabel'
3242
- label='Label (Optional) '
3243
- updateField={updateField}
3244
- tooltip={
3245
- <Tooltip style={{ textTransform: 'none' }}>
3246
- <Tooltip.Target>
3247
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3248
- </Tooltip.Target>
3249
- <Tooltip.Content>
3250
- <p>When a label is provided, the default city style will appear in the legend.</p>
3251
- </Tooltip.Content>
3252
- </Tooltip>
3253
- }
3254
- />
3255
- </>
3256
- )}
3156
+ {(config.general.geoType === 'us' ||
3157
+ config.general.geoType === 'us-county' ||
3158
+ config.general.geoType === 'world') && (
3159
+ <>
3160
+ <label>
3161
+ <span className='edit-label'>Default City Style</span>
3162
+ <select
3163
+ value={config.visual.cityStyle || false}
3164
+ onChange={event => {
3165
+ handleEditorChanges('handleCityStyle', event.target.value)
3166
+ }}
3167
+ >
3168
+ <option value='circle'>Circle</option>
3169
+ <option value='pin'>Pin</option>
3170
+ <option value='square'>Square</option>
3171
+ <option value='triangle'>Triangle</option>
3172
+ <option value='diamond'>Diamond</option>
3173
+ <option value='star'>Star</option>
3174
+ </select>
3175
+ </label>
3176
+ <TextField
3177
+ value={config.visual.cityStyleLabel}
3178
+ section='visual'
3179
+ fieldName='cityStyleLabel'
3180
+ label='Label (Optional) '
3181
+ updateField={updateField}
3182
+ tooltip={
3183
+ <Tooltip style={{ textTransform: 'none' }}>
3184
+ <Tooltip.Target>
3185
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3186
+ </Tooltip.Target>
3187
+ <Tooltip.Content>
3188
+ <p>When a label is provided, the default city style will appear in the legend.</p>
3189
+ </Tooltip.Content>
3190
+ </Tooltip>
3191
+ }
3192
+ />
3193
+ </>
3194
+ )}
3257
3195
  {/* <AdditionalCityStyles /> */}
3258
3196
  <>
3259
- {state.visual.additionalCityStyles.length > 0 &&
3260
- state.visual.additionalCityStyles.map(({ label, column, value, shape }, i) => {
3197
+ {config.visual.additionalCityStyles.length > 0 &&
3198
+ config.visual.additionalCityStyles.map(({ label, column, value, shape }, i) => {
3261
3199
  return (
3262
3200
  <div className='edit-block' key={`additional-city-style-${i}`}>
3263
3201
  <button
@@ -3330,7 +3268,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3330
3268
  type='number'
3331
3269
  min={0}
3332
3270
  max={100}
3333
- value={state.tooltips.opacity ? state.tooltips.opacity : 100}
3271
+ value={config.tooltips.opacity ? config.tooltips.opacity : 100}
3334
3272
  section='tooltips'
3335
3273
  fieldName='opacity'
3336
3274
  label='Tooltip Opacity (%)'
@@ -3338,7 +3276,7 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3338
3276
  />
3339
3277
  </label>
3340
3278
  {/* Leaflet Map Type */}
3341
- {state.general.geoType === 'leaflet' && (
3279
+ {config.general.geoType === 'leaflet' && (
3342
3280
  <>
3343
3281
  <Select
3344
3282
  label='Leaflet Theme'
@@ -3356,9 +3294,9 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3356
3294
  <AccordionItemButton>Custom Map Layers</AccordionItemButton>
3357
3295
  </AccordionItemHeading>
3358
3296
  <AccordionItemPanel>
3359
- {state.map.layers.length === 0 && <p>There are currently no layers.</p>}
3297
+ {config.map.layers.length === 0 && <p>There are currently no layers.</p>}
3360
3298
 
3361
- {state.map.layers.map((layer, index) => {
3299
+ {config.map.layers.map((layer, index) => {
3362
3300
  return (
3363
3301
  <>
3364
3302
  <Accordion allowZeroExpanded>
@@ -3444,10 +3382,10 @@ const EditorPanel = ({ columnsRequiredChecker }) => {
3444
3382
  </p>
3445
3383
  </AccordionItemPanel>
3446
3384
  </AccordionItem>
3447
- {state.general.geoType === 'us' && <Panels.PatternSettings name='Pattern Settings' />}
3448
- {state.general.geoType !== 'us-county' && <Panels.Annotate name='Text Annotations' />}
3385
+ {config.general.geoType === 'us' && <Panels.PatternSettings name='Pattern Settings' />}
3386
+ {config.general.geoType !== 'us-county' && <Panels.Annotate name='Text Annotations' />}
3449
3387
  </Accordion>
3450
- <AdvancedEditor loadConfig={loadConfig} config={state} convertStateToConfig={convertStateToConfig} />
3388
+ <AdvancedEditor loadConfig={setConfig} config={config} convertStateToConfig={convertStateToConfig} />
3451
3389
  </Layout.Sidebar>
3452
3390
  </ErrorBoundary>
3453
3391
  )