@cdc/map 4.26.2 → 4.26.3

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 (65) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcmap-vr9HZwRt.es.js +6 -0
  3. package/dist/cdcmap.js +26781 -24615
  4. package/examples/private/annotation-bug.json +642 -0
  5. package/package.json +3 -3
  6. package/src/CdcMap.tsx +3 -14
  7. package/src/CdcMapComponent.tsx +214 -159
  8. package/src/_stories/CdcMap.Defaults.stories.tsx +76 -0
  9. package/src/_stories/CdcMap.Editor.stories.tsx +187 -14
  10. package/src/_stories/CdcMap.stories.tsx +11 -1
  11. package/src/_stories/Map.HTMLInDataTable.stories.tsx +385 -0
  12. package/src/_stories/_mock/multi-state-show-unselected.json +82 -0
  13. package/src/cdcMapComponent.styles.css +2 -2
  14. package/src/components/Annotation/Annotation.Draggable.styles.css +4 -4
  15. package/src/components/Annotation/AnnotationDropdown.styles.css +1 -1
  16. package/src/components/Annotation/AnnotationList.styles.css +13 -13
  17. package/src/components/EditorPanel/components/EditorPanel.tsx +426 -58
  18. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings-style.css +1 -1
  19. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +5 -2
  20. package/src/components/EditorPanel/components/editorPanel.styles.css +34 -24
  21. package/src/components/Legend/components/Legend.tsx +9 -4
  22. package/src/components/Legend/components/LegendGroup/legend.group.css +5 -5
  23. package/src/components/Legend/components/index.scss +2 -3
  24. package/src/components/NavigationMenu.tsx +2 -1
  25. package/src/components/SmallMultiples/SmallMultiples.css +5 -5
  26. package/src/components/UsaMap/components/SingleState/SingleState.StateOutput.tsx +32 -17
  27. package/src/components/UsaMap/components/TerritoriesSection.tsx +3 -2
  28. package/src/components/UsaMap/components/Territory/Territory.Rectangle.tsx +13 -8
  29. package/src/components/UsaMap/components/UsaMap.County.tsx +410 -183
  30. package/src/components/UsaMap/components/UsaMap.Region.styles.css +1 -1
  31. package/src/components/UsaMap/components/UsaMap.SingleState.styles.css +2 -2
  32. package/src/components/UsaMap/components/UsaMap.State.tsx +13 -8
  33. package/src/components/WorldMap/WorldMap.tsx +10 -13
  34. package/src/components/WorldMap/data/world-topo-updated.json +1 -0
  35. package/src/components/WorldMap/data/world-topo.json +1 -1
  36. package/src/components/WorldMap/worldMap.styles.css +1 -1
  37. package/src/components/ZoomControls.tsx +49 -18
  38. package/src/components/zoomControls.styles.css +27 -11
  39. package/src/data/initial-state.js +14 -5
  40. package/src/data/legacy-defaults.ts +8 -0
  41. package/src/data/supported-geos.js +19 -0
  42. package/src/helpers/colors.ts +2 -1
  43. package/src/helpers/dataTableHelpers.ts +56 -0
  44. package/src/helpers/displayGeoName.ts +19 -11
  45. package/src/helpers/getMapContainerClasses.ts +8 -2
  46. package/src/helpers/getMatchingPatternForRow.ts +67 -0
  47. package/src/helpers/getPatternForRow.ts +11 -18
  48. package/src/helpers/tests/dataTableHelpers.test.ts +78 -0
  49. package/src/helpers/tests/displayGeoName.test.ts +17 -0
  50. package/src/helpers/tests/getMatchingPatternForRow.test.ts +150 -0
  51. package/src/helpers/tests/getPatternForRow.test.ts +140 -2
  52. package/src/helpers/urlDataHelpers.ts +7 -1
  53. package/src/hooks/useResizeObserver.ts +36 -22
  54. package/src/hooks/useTooltip.test.tsx +64 -0
  55. package/src/hooks/useTooltip.ts +28 -8
  56. package/src/scss/editor-panel.scss +1 -1
  57. package/src/scss/main.scss +140 -6
  58. package/src/scss/map.scss +9 -4
  59. package/src/store/map.actions.ts +2 -0
  60. package/src/store/map.reducer.ts +4 -0
  61. package/src/test/CdcMap.test.jsx +2 -2
  62. package/src/types/MapConfig.ts +22 -4
  63. package/src/types/MapContext.ts +3 -1
  64. package/dist/cdcmap-Cf9_fbQf.es.js +0 -6
  65. package/src/helpers/componentHelpers.ts +0 -8
@@ -0,0 +1,150 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { getMatchingPatternForRow } from '../getMatchingPatternForRow'
3
+ import { PatternSelection } from '../../types/MapConfig'
4
+
5
+ describe('getMatchingPatternForRow', () => {
6
+ it('uses the last matching specific pattern when multiple specific patterns match', () => {
7
+ const row = { Rate: 55 }
8
+ const patterns: PatternSelection[] = [
9
+ {
10
+ dataKey: 'Rate',
11
+ dataValue: '55',
12
+ pattern: 'lines',
13
+ size: 'small',
14
+ color: '#111',
15
+ label: '',
16
+ contrastCheck: true
17
+ },
18
+ {
19
+ dataKey: 'Rate',
20
+ dataValue: '55',
21
+ pattern: 'circles',
22
+ size: 'medium',
23
+ color: '#000',
24
+ label: '',
25
+ contrastCheck: true
26
+ }
27
+ ]
28
+
29
+ const result = getMatchingPatternForRow(row, patterns)
30
+
31
+ expect(result?.patternIndex).toBe(1)
32
+ expect(result?.pattern.pattern).toBe('circles')
33
+ })
34
+
35
+ it('matches specific dataKey patterns first', () => {
36
+ const row = { Rate: 55, Status: '55' }
37
+ const patterns: PatternSelection[] = [
38
+ {
39
+ dataKey: '',
40
+ dataValue: '55',
41
+ pattern: 'lines',
42
+ size: 'small',
43
+ color: '#111',
44
+ label: '',
45
+ contrastCheck: true
46
+ },
47
+ {
48
+ dataKey: 'Rate',
49
+ dataValue: '55',
50
+ pattern: 'circles',
51
+ size: 'medium',
52
+ color: '#000',
53
+ label: '',
54
+ contrastCheck: true
55
+ }
56
+ ]
57
+
58
+ const result = getMatchingPatternForRow(row, patterns)
59
+
60
+ expect(result?.patternIndex).toBe(1)
61
+ expect(result?.matchedDataKey).toBe('Rate')
62
+ expect(result?.pattern.pattern).toBe('circles')
63
+ })
64
+
65
+ it('falls back to broad matching when dataKey is blank', () => {
66
+ const row = { State: 'Colorado', Rate: 55 }
67
+ const patterns: PatternSelection[] = [
68
+ {
69
+ dataKey: '',
70
+ dataValue: 'Colorado',
71
+ pattern: 'waves',
72
+ size: 'large',
73
+ color: '#333',
74
+ label: '',
75
+ contrastCheck: true
76
+ }
77
+ ]
78
+
79
+ const result = getMatchingPatternForRow(row, patterns)
80
+
81
+ expect(result?.patternIndex).toBe(0)
82
+ expect(result?.matchedDataKey).toBe('State')
83
+ })
84
+
85
+ it('does not match when dataValue is empty', () => {
86
+ const row = { State: 'Colorado', Rate: 55 }
87
+ const patterns: PatternSelection[] = [
88
+ {
89
+ dataKey: '',
90
+ dataValue: ' ',
91
+ pattern: 'waves',
92
+ size: 'large',
93
+ color: '#333',
94
+ label: '',
95
+ contrastCheck: true
96
+ }
97
+ ]
98
+
99
+ expect(getMatchingPatternForRow(row, patterns)).toBeNull()
100
+ })
101
+
102
+ it('supports numeric string and number matching for broad patterns', () => {
103
+ const row = { Rate: 55 }
104
+ const patterns: PatternSelection[] = [
105
+ {
106
+ dataKey: '',
107
+ dataValue: '55',
108
+ pattern: 'waves',
109
+ size: 'large',
110
+ color: '#333',
111
+ label: '',
112
+ contrastCheck: true
113
+ }
114
+ ]
115
+
116
+ const result = getMatchingPatternForRow(row, patterns)
117
+
118
+ expect(result?.matchedDataKey).toBe('Rate')
119
+ expect(result?.patternIndex).toBe(0)
120
+ })
121
+
122
+ it('uses the last matching broad pattern when multiple broad patterns match', () => {
123
+ const row = { Category: 'Target' }
124
+ const patterns: PatternSelection[] = [
125
+ {
126
+ dataKey: '',
127
+ dataValue: 'Target',
128
+ pattern: 'lines',
129
+ size: 'small',
130
+ color: '#111',
131
+ label: '',
132
+ contrastCheck: true
133
+ },
134
+ {
135
+ dataKey: '',
136
+ dataValue: 'Target',
137
+ pattern: 'waves',
138
+ size: 'large',
139
+ color: '#333',
140
+ label: '',
141
+ contrastCheck: true
142
+ }
143
+ ]
144
+
145
+ const result = getMatchingPatternForRow(row, patterns)
146
+
147
+ expect(result?.patternIndex).toBe(1)
148
+ expect(result?.pattern.pattern).toBe('waves')
149
+ })
150
+ })
@@ -4,8 +4,24 @@ import { getPatternForRow } from '../getPatternForRow'
4
4
  const baseConfig: any = {
5
5
  map: {
6
6
  patterns: [
7
- { dataKey: 'Percent Vaccinated', dataValue: '99.99', pattern: 'circles', size: 'medium', color: '#000' },
8
- { dataKey: 'Status', dataValue: 'NA', pattern: 'lines', size: 'small', color: '#111' }
7
+ {
8
+ dataKey: 'Percent Vaccinated',
9
+ dataValue: '99.99',
10
+ pattern: 'circles',
11
+ size: 'medium',
12
+ color: '#000',
13
+ label: '',
14
+ contrastCheck: true
15
+ },
16
+ {
17
+ dataKey: 'Status',
18
+ dataValue: 'NA',
19
+ pattern: 'lines',
20
+ size: 'small',
21
+ color: '#111',
22
+ label: '',
23
+ contrastCheck: true
24
+ }
9
25
  ]
10
26
  }
11
27
  }
@@ -36,4 +52,126 @@ describe('getPatternForRow', () => {
36
52
  const row = { 'Percent Vaccinated': 75.06, Status: '*' }
37
53
  expect(getPatternForRow(row, baseConfig)).toBeNull()
38
54
  })
55
+
56
+ it('matches blank dataKey patterns against any row value', () => {
57
+ const config = {
58
+ map: {
59
+ patterns: [
60
+ {
61
+ dataKey: '',
62
+ dataValue: 'Colorado',
63
+ pattern: 'waves',
64
+ size: 'large',
65
+ color: '#222',
66
+ label: '',
67
+ contrastCheck: true
68
+ }
69
+ ]
70
+ }
71
+ }
72
+ const row = { STATE: 'Colorado', Rate: 55 }
73
+ const result = getPatternForRow(row, config)
74
+
75
+ expect(result).toEqual({
76
+ pattern: 'waves',
77
+ dataKey: 'STATE',
78
+ size: 'large',
79
+ patternIndex: 0,
80
+ color: '#222'
81
+ })
82
+ })
83
+
84
+ it('prioritizes specific dataKey matches over broad matches', () => {
85
+ const config = {
86
+ map: {
87
+ patterns: [
88
+ {
89
+ dataKey: '',
90
+ dataValue: '55',
91
+ pattern: 'lines',
92
+ size: 'small',
93
+ color: '#111',
94
+ label: '',
95
+ contrastCheck: true
96
+ },
97
+ {
98
+ dataKey: 'Rate',
99
+ dataValue: '55',
100
+ pattern: 'circles',
101
+ size: 'medium',
102
+ color: '#000',
103
+ label: '',
104
+ contrastCheck: true
105
+ }
106
+ ]
107
+ }
108
+ }
109
+ const row = { Rate: 55, Category: '55' }
110
+ const result = getPatternForRow(row, config)
111
+
112
+ expect(result).toEqual({
113
+ pattern: 'circles',
114
+ dataKey: 'Rate',
115
+ size: 'medium',
116
+ patternIndex: 1,
117
+ color: '#000'
118
+ })
119
+ })
120
+
121
+ it('does not match blank dataKey patterns with empty values', () => {
122
+ const config = {
123
+ map: {
124
+ patterns: [
125
+ {
126
+ dataKey: '',
127
+ dataValue: ' ',
128
+ pattern: 'lines',
129
+ size: 'small',
130
+ color: '#111',
131
+ label: '',
132
+ contrastCheck: true
133
+ }
134
+ ]
135
+ }
136
+ }
137
+ const row = { STATE: 'Colorado' }
138
+ expect(getPatternForRow(row, config)).toBeNull()
139
+ })
140
+
141
+ it('returns the last matching specific pattern to preserve dominant visual overlay behavior', () => {
142
+ const config = {
143
+ map: {
144
+ patterns: [
145
+ {
146
+ dataKey: 'Rate',
147
+ dataValue: '55',
148
+ pattern: 'lines',
149
+ size: 'small',
150
+ color: '#111',
151
+ label: '',
152
+ contrastCheck: true
153
+ },
154
+ {
155
+ dataKey: 'Rate',
156
+ dataValue: '55',
157
+ pattern: 'waves',
158
+ size: 'large',
159
+ color: '#222',
160
+ label: '',
161
+ contrastCheck: true
162
+ }
163
+ ]
164
+ }
165
+ }
166
+ const row = { Rate: 55 }
167
+ const result = getPatternForRow(row, config)
168
+
169
+ expect(result).toEqual({
170
+ pattern: 'waves',
171
+ dataKey: 'Rate',
172
+ size: 'large',
173
+ patternIndex: 1,
174
+ color: '#222'
175
+ })
176
+ })
39
177
  })
@@ -5,6 +5,7 @@ import { isSolrCsv, isSolrJson } from '@cdc/core/helpers/isSolr'
5
5
  import { MapConfig } from '../types/MapConfig'
6
6
  import { CSV_PARSE_CONFIG } from './constants'
7
7
  import { cloneConfig } from '@cdc/core/helpers/cloneConfig'
8
+ import { extractDataAndMetadata } from '@cdc/core/helpers/extractDataAndMetadata'
8
9
 
9
10
  const buildQueryString = (params: Record<string, string>): string =>
10
11
  Object.keys(params)
@@ -34,6 +35,7 @@ export const reloadURLData = async (config: MapConfig, setConfig: (config: MapCo
34
35
 
35
36
  let dataUrlFinal = `${dataUrl.origin}${dataUrl.pathname}${buildQueryString(qsParams)}`
36
37
  let data
38
+ let dataMetadata: Record<string, string> = {}
37
39
 
38
40
  try {
39
41
  const regex = /(?:\.([^.]+))?$/
@@ -47,7 +49,10 @@ export const reloadURLData = async (config: MapConfig, setConfig: (config: MapCo
47
49
  return parsedCsv.data
48
50
  })
49
51
  } else if ('json' === ext || isSolrJson(dataUrlFinal)) {
50
- data = await fetch(dataUrlFinal).then(response => response.json())
52
+ const json = await fetch(dataUrlFinal).then(response => response.json())
53
+ const extracted = extractDataAndMetadata(json)
54
+ data = extracted.data
55
+ dataMetadata = extracted.dataMetadata
51
56
  } else {
52
57
  data = []
53
58
  }
@@ -64,6 +69,7 @@ export const reloadURLData = async (config: MapConfig, setConfig: (config: MapCo
64
69
 
65
70
  const newConfig = cloneConfig(config)
66
71
  newConfig.data = data
72
+ newConfig.dataMetadata = dataMetadata
67
73
  newConfig.runtimeDataUrl = dataUrlFinal
68
74
 
69
75
  setConfig(newConfig)
@@ -1,4 +1,4 @@
1
- import { useState, useCallback, useEffect } from 'react'
1
+ import { useState, useCallback, useRef } from 'react'
2
2
  import { type ViewPort } from '@cdc/core/types/ViewPort'
3
3
  import { type DimensionsType } from '@cdc/core/types/Dimensions'
4
4
  import { EDITOR_WIDTH } from '@cdc/core/helpers/constants'
@@ -11,37 +11,51 @@ export const useResizeObserver = (isEditor: boolean) => {
11
11
  const [vizViewport, setVizViewport] = useState<ViewPort>(null)
12
12
  const [container, setContainer] = useState<HTMLElement | null>(null)
13
13
 
14
- const resizeObserver = new ResizeObserver(entries => {
15
- for (let entry of entries) {
16
- let { width, height } = entry.contentRect
14
+ // Keep isEditor fresh in the observer callback without recreating the observer
15
+ const isEditorRef = useRef(isEditor)
16
+ isEditorRef.current = isEditor
17
17
 
18
- const editorIsOpen = isEditor && !!document.querySelector('.editor-panel:not(.hidden)')
19
- width = editorIsOpen ? width - EDITOR_WIDTH : width
18
+ const resizeObserverRef = useRef<ResizeObserver | null>(null)
20
19
 
21
- // Account for 1rem padding in editor mode
22
- width = width - (isEditor ? 36 : 0)
20
+ const outerContainerRef = useCallback(node => {
21
+ // Tear down any previous observer (node swap or unmount)
22
+ if (resizeObserverRef.current) {
23
+ resizeObserverRef.current.disconnect()
24
+ resizeObserverRef.current = null
25
+ }
23
26
 
24
- const newViewport = getViewport(width)
27
+ if (node !== null) {
28
+ resizeObserverRef.current = new ResizeObserver(entries => {
29
+ for (let entry of entries) {
30
+ let { width, height } = entry.contentRect
25
31
 
26
- setCurrentViewport(newViewport)
27
- setVizViewport(newViewport)
32
+ const editorIsOpen = isEditorRef.current && !!document.querySelector('.editor-panel:not(.hidden)')
33
+ width = editorIsOpen ? width - EDITOR_WIDTH : width
28
34
 
29
- setDimensions([width, height])
30
- }
31
- })
35
+ // Account for 1rem padding in editor mode
36
+ width = width - (isEditorRef.current ? 36 : 0)
32
37
 
33
- const outerContainerRef = useCallback(node => {
34
- if (node !== null) {
35
- resizeObserver.observe(node)
36
- }
37
- setContainer(node)
38
+ const newViewport = getViewport(width)
38
39
 
39
- return () => {
40
- resizeObserver.disconnect()
40
+ setCurrentViewport(newViewport)
41
+ setVizViewport(newViewport)
42
+ setDimensions([width, height])
43
+ }
44
+ })
45
+ resizeObserverRef.current.observe(node)
41
46
  }
47
+
48
+ setContainer(node)
42
49
  }, [])
43
50
 
44
- return { resizeObserver, dimensions, currentViewport, vizViewport, outerContainerRef, container }
51
+ return {
52
+ resizeObserver: resizeObserverRef.current,
53
+ dimensions,
54
+ currentViewport,
55
+ vizViewport,
56
+ outerContainerRef,
57
+ container
58
+ }
45
59
  }
46
60
 
47
61
  export default useResizeObserver
@@ -0,0 +1,64 @@
1
+ import { renderHook } from '@testing-library/react'
2
+ import useTooltip from './useTooltip'
3
+
4
+ const supportedStatesFipsCodes = {
5
+ '01': 'Alabama'
6
+ }
7
+
8
+ const createConfig = (hideGeoColumnInTooltip: boolean) => ({
9
+ general: {
10
+ geoType: 'world',
11
+ type: 'map',
12
+ hideGeoColumnInTooltip,
13
+ hidePrimaryColumnInTooltip: false,
14
+ geoLabelOverride: ''
15
+ },
16
+ columns: {
17
+ geo: {
18
+ name: 'Country',
19
+ label: 'Location',
20
+ tooltip: true,
21
+ displayColumn: ''
22
+ },
23
+ primary: {
24
+ name: 'Value',
25
+ label: 'Value',
26
+ tooltip: true
27
+ },
28
+ navigate: {
29
+ name: ''
30
+ }
31
+ },
32
+ legend: {
33
+ specialClasses: []
34
+ },
35
+ tooltips: {
36
+ noDataLabel: 'No Data'
37
+ }
38
+ })
39
+
40
+ describe('useTooltip', () => {
41
+ it('hides the geography column label in the tooltip body when configured', () => {
42
+ const row = { Country: 'ssd', Value: 10 }
43
+
44
+ const { result: visibleResult } = renderHook(() =>
45
+ useTooltip({
46
+ config: createConfig(false),
47
+ supportedStatesFipsCodes
48
+ })
49
+ )
50
+ const { result: hiddenResult } = renderHook(() =>
51
+ useTooltip({
52
+ config: createConfig(true),
53
+ supportedStatesFipsCodes
54
+ })
55
+ )
56
+
57
+ const visibleTooltip = visibleResult.current.buildTooltip(row, 'South Sudan')
58
+ const hiddenTooltip = hiddenResult.current.buildTooltip(row, 'South Sudan')
59
+
60
+ expect(visibleTooltip).toContain('Location: South Sudan')
61
+ expect(hiddenTooltip).not.toContain('Location: South Sudan')
62
+ expect(hiddenTooltip).toContain('<li class="tooltip-body">South Sudan</li>')
63
+ })
64
+ })
@@ -27,8 +27,9 @@ const useTooltip = props => {
27
27
  * @param {String} geoName - feature name
28
28
  * @returns {String} text to be appended to toolTipText
29
29
  */
30
- const handleTooltipGeoColumn = (geoName: string) => {
30
+ const handleTooltipGeoColumn = (geoName: string, row?) => {
31
31
  const { hideGeoColumnInTooltip } = config.general as { hideGeoColumnInTooltip: boolean }
32
+ const displayOverride = row?.[config.columns.geo?.displayColumn]
32
33
 
33
34
  const handleTooltipPrefix = (toolTipText: string) => {
34
35
  const { geoType, geoLabelOverride } = config.general
@@ -54,8 +55,11 @@ const useTooltip = props => {
54
55
 
55
56
  const prefix = handleTooltipPrefix('')
56
57
 
57
- if (hideGeoColumnInTooltip) return `<strong>${displayGeoName(geoName)}</strong>`
58
- return `<p class="tooltip-heading" style="text-transform: none;">${prefix}${displayGeoName(geoName)}</p>`
58
+ if (hideGeoColumnInTooltip) return `<strong>${displayGeoName(geoName, displayOverride)}</strong>`
59
+ return `<p class="tooltip-heading" style="text-transform: none;">${prefix}${displayGeoName(
60
+ geoName,
61
+ displayOverride
62
+ )}</p>`
59
63
  }
60
64
 
61
65
  /**
@@ -74,13 +78,29 @@ const useTooltip = props => {
74
78
  }
75
79
 
76
80
  const handleTooltipPrimaryColumn = (tooltipValue, column) => {
77
- const { hidePrimaryColumnInTooltip } = config.general as { hidePrimaryColumnInTooltip: boolean }
81
+ const { hidePrimaryColumnInTooltip, hideGeoColumnInTooltip } = config.general as {
82
+ hidePrimaryColumnInTooltip: boolean
83
+ hideGeoColumnInTooltip: boolean
84
+ }
78
85
  let tooltipPrefix = column.label?.length > 0 ? column.label : ''
79
- if ((column.name === config.columns.primary.name && hidePrimaryColumnInTooltip) || !tooltipPrefix)
80
- return `<li class="tooltip-body">${tooltipValue}</li>`
86
+ const hidePrimaryLabel = column.name === config.columns.primary.name && hidePrimaryColumnInTooltip
87
+ const hideGeoLabel = column.name === config.columns.geo.name && hideGeoColumnInTooltip
88
+
89
+ if (hidePrimaryLabel || hideGeoLabel || !tooltipPrefix) return `<li class="tooltip-body">${tooltipValue}</li>`
81
90
  return `<li class="tooltip-body">${tooltipPrefix}: ${tooltipValue}</li>`
82
91
  }
83
92
 
93
+ const formatTooltipColumnValue = (row, column, columnKey) => {
94
+ if (!row) return config.tooltips?.noDataLabel || 'No Data'
95
+
96
+ if (column.name === config.columns.geo.name) {
97
+ const displayOverride = row?.[config.columns.geo?.displayColumn]
98
+ return displayGeoName(row[column.name], displayOverride)
99
+ }
100
+
101
+ return displayDataAsText(row[column.name], columnKey, config)
102
+ }
103
+
84
104
  /**
85
105
  *
86
106
  * @param {String} toolTipText - previous tooltipText to build upon
@@ -106,7 +126,7 @@ const useTooltip = props => {
106
126
  let tooltipValue = handleTooltipSpecialClassText(specialClasses, column, row, '', columnKey)
107
127
 
108
128
  if (!tooltipValue) {
109
- tooltipValue = row ? displayDataAsText(row[column.name], columnKey, config) : 'No Data'
129
+ tooltipValue = formatTooltipColumnValue(row, column, columnKey)
110
130
  }
111
131
 
112
132
  toolTipText += handleTooltipPrimaryColumn(tooltipValue, column)
@@ -125,7 +145,7 @@ const useTooltip = props => {
125
145
  toolTipText += handleTooltipStateNameColumn(toolTipText, row)
126
146
 
127
147
  // Handle Columns > Data Column In tooltips
128
- toolTipText += handleTooltipGeoColumn(geoName)
148
+ toolTipText += handleTooltipGeoColumn(geoName, row)
129
149
 
130
150
  // Handle Columns > Geography Column In tooltips
131
151
  toolTipText = handleTooltipColumns(toolTipText, row)
@@ -18,7 +18,7 @@
18
18
  }
19
19
  }
20
20
 
21
- .cdc-open-viz-module {
21
+ .cove-visualization {
22
22
  .editor-panel {
23
23
  .cove-input-group,
24
24
  .cove-accordion__small-inputs {