@cdc/map 4.23.2 → 4.23.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.
- package/dist/cdcmap.js +21645 -21544
- package/examples/default-county.json +1 -1
- package/examples/default-geocode.json +744 -744
- package/examples/default-hex.json +3 -5
- package/examples/example-city-state-no-territories.json +703 -0
- package/examples/example-city-state.json +4 -7
- package/examples/example-city-stateBAD.json +744 -0
- package/examples/gallery/city-state.json +478 -478
- package/examples/world-geocode-data.json +18 -0
- package/examples/world-geocode.json +108 -0
- package/index.html +34 -29
- package/package.json +6 -3
- package/src/CdcMap.jsx +127 -64
- package/src/components/CityList.jsx +35 -35
- package/src/components/CountyMap.jsx +285 -447
- package/src/components/DataTable.jsx +7 -31
- package/src/components/EditorPanel.jsx +227 -102
- package/src/components/Sidebar.jsx +2 -0
- package/src/components/UsaMap.jsx +24 -19
- package/src/components/WorldMap.jsx +40 -8
- package/src/data/feature-test.json +73 -0
- package/src/data/initial-state.js +3 -0
- package/src/data/supported-geos.js +7 -7
- package/src/scss/map.scss +12 -0
- package/src/test/CdcMap.test.jsx +19 -0
- package/vite.config.js +3 -3
- package/src/hooks/useColorPalette.ts +0 -88
|
@@ -79,6 +79,7 @@ const UsaMap = props => {
|
|
|
79
79
|
isFilterValueSupported = true
|
|
80
80
|
}
|
|
81
81
|
})
|
|
82
|
+
|
|
82
83
|
Object.keys(supportedTerritories).forEach(supportedTerritory => {
|
|
83
84
|
if (supportedTerritories[supportedTerritory].indexOf(setSharedFilterValue.toUpperCase()) !== -1) {
|
|
84
85
|
isFilterValueSupported = true
|
|
@@ -109,11 +110,15 @@ const UsaMap = props => {
|
|
|
109
110
|
const territoriesKeys = Object.keys(supportedTerritories) // data will have already mapped abbreviated territories to their full names
|
|
110
111
|
|
|
111
112
|
useEffect(() => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
if (state.general.territoriesAlwaysShow) {
|
|
114
|
+
// show all Territories whether in the data or not
|
|
115
|
+
setTerritoriesData(territoriesKeys)
|
|
116
|
+
} else {
|
|
117
|
+
// Territories need to show up if they're in the data at all, not just if they're "active". That's why this is different from Cities
|
|
118
|
+
const territoriesList = territoriesKeys.filter(key => data[key])
|
|
119
|
+
setTerritoriesData(territoriesList)
|
|
120
|
+
}
|
|
121
|
+
}, [data, state.general.territoriesAlwaysShow]) // eslint-disable-line
|
|
117
122
|
|
|
118
123
|
const geoStrokeColor = state.general.geoBorderColor === 'darkGray' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255,255,255,0.7)'
|
|
119
124
|
|
|
@@ -167,8 +172,8 @@ const UsaMap = props => {
|
|
|
167
172
|
}
|
|
168
173
|
|
|
169
174
|
return <Shape key={label} label={label} css={styles} text={styles.color} strokeWidth={1.5} textColor={textColor} onClick={() => geoClickHandler(territory, territoryData)}
|
|
170
|
-
|
|
171
|
-
|
|
175
|
+
data-tooltip-id="tooltip"
|
|
176
|
+
data-tooltip-html={toolTip}
|
|
172
177
|
/>
|
|
173
178
|
}
|
|
174
179
|
})
|
|
@@ -292,10 +297,10 @@ const UsaMap = props => {
|
|
|
292
297
|
return (
|
|
293
298
|
<g data-name={geoName} key={key}>
|
|
294
299
|
<g className='geo-group' css={styles} onClick={() => geoClickHandler(geoDisplayName, geoData)}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
300
|
+
id={geoName}
|
|
301
|
+
data-tooltip-id="tooltip"
|
|
302
|
+
data-tooltip-html={tooltip}
|
|
303
|
+
>
|
|
299
304
|
<path tabIndex={-1} className='single-geo' strokeWidth={1.3} d={path} />
|
|
300
305
|
{(isHex || showLabel) && geoLabel(geo, legendColors[0], projection)}
|
|
301
306
|
</g>
|
|
@@ -319,18 +324,18 @@ const UsaMap = props => {
|
|
|
319
324
|
// Cities
|
|
320
325
|
geosJsx.push(
|
|
321
326
|
<CityList
|
|
322
|
-
|
|
323
|
-
key='cities'
|
|
324
|
-
data={data}
|
|
325
|
-
state={state}
|
|
326
|
-
geoClickHandler={geoClickHandler}
|
|
327
|
+
applyLegendToRow={applyLegendToRow}
|
|
327
328
|
applyTooltipsToGeo={applyTooltipsToGeo}
|
|
329
|
+
data={data}
|
|
328
330
|
displayGeoName={displayGeoName}
|
|
329
|
-
|
|
330
|
-
titleCase={titleCase}
|
|
331
|
-
setSharedFilterValue={setSharedFilterValue}
|
|
331
|
+
geoClickHandler={geoClickHandler}
|
|
332
332
|
isFilterValueSupported={isFilterValueSupported}
|
|
333
333
|
isGeoCodeMap={state.general.type === 'us-geocode'}
|
|
334
|
+
key='cities'
|
|
335
|
+
projection={projection}
|
|
336
|
+
setSharedFilterValue={setSharedFilterValue}
|
|
337
|
+
state={state}
|
|
338
|
+
titleCase={titleCase}
|
|
334
339
|
/>
|
|
335
340
|
)
|
|
336
341
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { memo } from 'react'
|
|
2
2
|
|
|
3
3
|
import { jsx } from '@emotion/react'
|
|
4
4
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
@@ -16,7 +16,21 @@ const { features: world } = feature(topoJSON, topoJSON.objects.countries)
|
|
|
16
16
|
let projection = geoMercator()
|
|
17
17
|
|
|
18
18
|
const WorldMap = props => {
|
|
19
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
state,
|
|
21
|
+
applyTooltipsToGeo,
|
|
22
|
+
data,
|
|
23
|
+
geoClickHandler,
|
|
24
|
+
applyLegendToRow,
|
|
25
|
+
displayGeoName,
|
|
26
|
+
supportedCountries,
|
|
27
|
+
setState, setRuntimeData,
|
|
28
|
+
generateRuntimeData,
|
|
29
|
+
setFilteredCountryCode,
|
|
30
|
+
position, setPosition,
|
|
31
|
+
hasZoom,
|
|
32
|
+
handleMapAriaLabels,
|
|
33
|
+
titleCase } = props
|
|
20
34
|
|
|
21
35
|
// TODO Refactor - state should be set together here to avoid rerenders
|
|
22
36
|
// Resets to original data & zooms out
|
|
@@ -58,6 +72,11 @@ const WorldMap = props => {
|
|
|
58
72
|
Reset Filters
|
|
59
73
|
</button>
|
|
60
74
|
)}
|
|
75
|
+
{state.general.type === 'world-geocode' && (
|
|
76
|
+
<button onClick={() => handleReset(state, setState, setRuntimeData, generateRuntimeData)} className='reset' aria-label='Reset Zoom'>
|
|
77
|
+
Reset Zoom
|
|
78
|
+
</button>
|
|
79
|
+
)}
|
|
61
80
|
</div>
|
|
62
81
|
)
|
|
63
82
|
|
|
@@ -76,7 +95,7 @@ const WorldMap = props => {
|
|
|
76
95
|
const geosJsx = geographies.map(({ feature: geo, path }, i) => {
|
|
77
96
|
const geoKey = geo.properties.iso
|
|
78
97
|
|
|
79
|
-
if (!geoKey) return
|
|
98
|
+
if (!geoKey) return null;
|
|
80
99
|
|
|
81
100
|
const geoData = data[geoKey]
|
|
82
101
|
|
|
@@ -104,13 +123,13 @@ const WorldMap = props => {
|
|
|
104
123
|
|
|
105
124
|
styles = {
|
|
106
125
|
...styles,
|
|
107
|
-
fill: legendColors[0],
|
|
126
|
+
fill: state.general.type !== 'world-geocode' ? legendColors[0] : '#E6E6E6',
|
|
108
127
|
cursor: 'default',
|
|
109
128
|
'&:hover': {
|
|
110
|
-
fill: legendColors[1]
|
|
129
|
+
fill: state.general.type !== 'world-geocode' ? legendColors[1] : '#E6E6E6'
|
|
111
130
|
},
|
|
112
131
|
'&:active': {
|
|
113
|
-
fill: legendColors[2]
|
|
132
|
+
fill: state.general.type !== 'world-geocode' ? legendColors[2] : '#E6E6E6'
|
|
114
133
|
}
|
|
115
134
|
}
|
|
116
135
|
|
|
@@ -136,7 +155,20 @@ const WorldMap = props => {
|
|
|
136
155
|
})
|
|
137
156
|
|
|
138
157
|
// Cities
|
|
139
|
-
geosJsx.push(
|
|
158
|
+
geosJsx.push(
|
|
159
|
+
<CityList
|
|
160
|
+
applyLegendToRow={applyLegendToRow}
|
|
161
|
+
applyTooltipsToGeo={applyTooltipsToGeo}
|
|
162
|
+
data={data}
|
|
163
|
+
displayGeoName={displayGeoName}
|
|
164
|
+
geoClickHandler={geoClickHandler}
|
|
165
|
+
isGeoCodeMap={state.general.type === 'world-geocode'}
|
|
166
|
+
key='cities'
|
|
167
|
+
projection={projection}
|
|
168
|
+
state={state}
|
|
169
|
+
titleCase={titleCase}
|
|
170
|
+
/>
|
|
171
|
+
)
|
|
140
172
|
|
|
141
173
|
// Bubbles
|
|
142
174
|
if (state.general.type === 'bubble') {
|
|
@@ -174,7 +206,7 @@ const WorldMap = props => {
|
|
|
174
206
|
</ZoomableGroup>
|
|
175
207
|
</svg>
|
|
176
208
|
)}
|
|
177
|
-
{(state.general.type === 'data' || (state.general.type === 'bubble' && hasZoom)) && <ZoomControls position={position} setPosition={setPosition} setRuntimeData={setRuntimeData} state={state} setState={setState} generateRuntimeData={generateRuntimeData} />}
|
|
209
|
+
{(state.general.type === 'data' || (state.general.type === 'world-geocode' && hasZoom) || (state.general.type === 'bubble' && hasZoom)) && <ZoomControls position={position} setPosition={setPosition} setRuntimeData={setRuntimeData} state={state} setState={setState} generateRuntimeData={generateRuntimeData} />}
|
|
178
210
|
</ErrorBoundary>
|
|
179
211
|
)
|
|
180
212
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "Topology",
|
|
3
|
+
"arcs": [
|
|
4
|
+
[
|
|
5
|
+
[
|
|
6
|
+
33,
|
|
7
|
+
100
|
|
8
|
+
],
|
|
9
|
+
[
|
|
10
|
+
-6,
|
|
11
|
+
9
|
|
12
|
+
],
|
|
13
|
+
[
|
|
14
|
+
30,
|
|
15
|
+
66
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
102,
|
|
19
|
+
-42
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
-118,
|
|
23
|
+
-133
|
|
24
|
+
],
|
|
25
|
+
[
|
|
26
|
+
11,
|
|
27
|
+
39
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
-52,
|
|
31
|
+
39
|
|
32
|
+
],
|
|
33
|
+
[
|
|
34
|
+
33,
|
|
35
|
+
22
|
|
36
|
+
]
|
|
37
|
+
]
|
|
38
|
+
],
|
|
39
|
+
"transform": {
|
|
40
|
+
"scale": [
|
|
41
|
+
0.04505085471698112,
|
|
42
|
+
0.04496205714285712
|
|
43
|
+
],
|
|
44
|
+
"translate": [
|
|
45
|
+
-116.2012448,
|
|
46
|
+
33.3764121
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"objects": {
|
|
50
|
+
"Untitled layer": {
|
|
51
|
+
"type": "GeometryCollection",
|
|
52
|
+
"geometries": [
|
|
53
|
+
{
|
|
54
|
+
"arcs": [
|
|
55
|
+
[
|
|
56
|
+
0
|
|
57
|
+
]
|
|
58
|
+
],
|
|
59
|
+
"type": "Polygon",
|
|
60
|
+
"properties": {
|
|
61
|
+
"name": "new",
|
|
62
|
+
"styleUrl": "#poly-000000-1200-77-nodesc",
|
|
63
|
+
"fill-opacity": 0.30196078431372547,
|
|
64
|
+
"fill": "#000000",
|
|
65
|
+
"stroke-opacity": 1,
|
|
66
|
+
"stroke": "#000000",
|
|
67
|
+
"stroke-width": 1.2
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -2,6 +2,7 @@ export default {
|
|
|
2
2
|
general: {
|
|
3
3
|
geoBorderColor: 'darkGray',
|
|
4
4
|
headerColor: 'theme-blue',
|
|
5
|
+
title: '',
|
|
5
6
|
showTitle: true,
|
|
6
7
|
showSidebar: true,
|
|
7
8
|
showDownloadButton: true,
|
|
@@ -9,6 +10,7 @@ export default {
|
|
|
9
10
|
displayAsHex: false,
|
|
10
11
|
displayStateLabels: false,
|
|
11
12
|
territoriesLabel: 'Territories',
|
|
13
|
+
territoriesAlwaysShow: false,
|
|
12
14
|
language: 'en',
|
|
13
15
|
geoType: 'single-state',
|
|
14
16
|
geoLabelOverride: '',
|
|
@@ -53,6 +55,7 @@ export default {
|
|
|
53
55
|
unified: false,
|
|
54
56
|
singleColumn: false,
|
|
55
57
|
singleRow: false,
|
|
58
|
+
showSpecialClassesLast: false,
|
|
56
59
|
dynamicDescription: false,
|
|
57
60
|
type: 'equalnumber',
|
|
58
61
|
numberOfItems: 3,
|
|
@@ -121,13 +121,13 @@ export const stateToIso = {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
export const stateFipsToTwoDigit = {
|
|
124
|
-
['01']: 'AL',
|
|
125
|
-
['02']: 'AK',
|
|
126
|
-
['04']: 'AZ',
|
|
127
|
-
['05']: 'AR',
|
|
128
|
-
['06']: 'CA',
|
|
129
|
-
['08']: 'CO',
|
|
130
|
-
['09']: 'CT',
|
|
124
|
+
['01']: 'AL', // eslint-disable-line
|
|
125
|
+
['02']: 'AK', // eslint-disable-line
|
|
126
|
+
['04']: 'AZ', // eslint-disable-line
|
|
127
|
+
['05']: 'AR', // eslint-disable-line
|
|
128
|
+
['06']: 'CA', // eslint-disable-line
|
|
129
|
+
['08']: 'CO', // eslint-disable-line
|
|
130
|
+
['09']: 'CT', // eslint-disable-line
|
|
131
131
|
10: 'DE',
|
|
132
132
|
11: 'DC',
|
|
133
133
|
12: 'FL',
|
package/src/scss/map.scss
CHANGED
|
@@ -225,6 +225,7 @@ header + .map-container.full-border {
|
|
|
225
225
|
position: absolute;
|
|
226
226
|
top: 10px;
|
|
227
227
|
right: 10px;
|
|
228
|
+
display: none;
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
//Region Maps
|
|
@@ -310,3 +311,14 @@ header + .map-container.full-border {
|
|
|
310
311
|
stroke-linecap: round;
|
|
311
312
|
pointer-events: none;
|
|
312
313
|
}
|
|
314
|
+
|
|
315
|
+
canvas {
|
|
316
|
+
width: 100%;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
#canvas-tooltip {
|
|
320
|
+
position: fixed;
|
|
321
|
+
background-color: white;
|
|
322
|
+
pointer-events: none;
|
|
323
|
+
display: none;
|
|
324
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
2
|
+
import CdcMap from './../CdcMap'
|
|
3
|
+
import usaConfig from './../../examples/example-city-state.json'
|
|
4
|
+
|
|
5
|
+
// Example: City State Map
|
|
6
|
+
describe('United States Map', () => {
|
|
7
|
+
it('loads', async () => {
|
|
8
|
+
render(<CdcMap config={usaConfig} />)
|
|
9
|
+
// screen.debug()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('accepts title changes', async () => {
|
|
13
|
+
render(<CdcMap config={usaConfig} isEditor />)
|
|
14
|
+
const titleInput = screen.getByTestId('title-input')
|
|
15
|
+
expect(titleInput.value).toBe('Example Data Map with Cities')
|
|
16
|
+
fireEvent.change(titleInput, { target: { value: 'My New Title' } })
|
|
17
|
+
expect(titleInput.value).toBe('My New Title')
|
|
18
|
+
})
|
|
19
|
+
})
|
package/vite.config.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import GenerateViteConfig from '../../generateViteConfig.js'
|
|
2
2
|
import { moduleName } from './package.json'
|
|
3
3
|
|
|
4
|
-
export default GenerateViteConfig(moduleName,null,{
|
|
4
|
+
export default GenerateViteConfig(moduleName, null, {
|
|
5
5
|
jsxImportSource: '@emotion/react',
|
|
6
6
|
babel: {
|
|
7
|
-
plugins: [
|
|
8
|
-
}
|
|
7
|
+
plugins: ['@emotion/babel-plugin']
|
|
8
|
+
}
|
|
9
9
|
})
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { useEffect, useReducer } from 'react'
|
|
2
|
-
|
|
3
|
-
// constants
|
|
4
|
-
const SEQUENTIAL = 'SEQUENTIAL'
|
|
5
|
-
const SEQUENTIAL_REVERSE = 'SEQUENTIAL_REVERSE'
|
|
6
|
-
export const GET_PALETTE = 'GET_PALETTE'
|
|
7
|
-
|
|
8
|
-
// types & interfaces
|
|
9
|
-
interface State {
|
|
10
|
-
readonly filteredPallets: string[]
|
|
11
|
-
readonly filteredQualitative: string[]
|
|
12
|
-
readonly isPaletteReversed: boolean
|
|
13
|
-
paletteName: string | undefined
|
|
14
|
-
}
|
|
15
|
-
interface Action<Palettes> {
|
|
16
|
-
type: 'SEQUENTIAL' | 'SEQUENTIAL_REVERSE' | 'GET_PALETTE'
|
|
17
|
-
payload: Palettes
|
|
18
|
-
paletteName?: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// create initial state
|
|
22
|
-
const initialState: State = {
|
|
23
|
-
filteredPallets: [],
|
|
24
|
-
isPaletteReversed: false,
|
|
25
|
-
filteredQualitative: [],
|
|
26
|
-
paletteName: undefined
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// create reducer function to handle multiple states & manupilate with each state
|
|
30
|
-
function reducer<T>(state: State, action: Action<T>): State {
|
|
31
|
-
// <T> refers to generic type
|
|
32
|
-
const palletNamesArr: string[] = Object.keys(action.payload) // action.payload === colorPalettes object
|
|
33
|
-
let reverseRegex = new RegExp('reverse$') // matches a string that ends in with "reverse".
|
|
34
|
-
let qualitativeRegex = new RegExp('^qualitative') //matches any string that starts with "qualitative".
|
|
35
|
-
let paletteName: string = ''
|
|
36
|
-
switch (action.type) {
|
|
37
|
-
case GET_PALETTE:
|
|
38
|
-
// this case runs first time when page loads and then every time when color.state changes.It is mounted insude of useEffect on Editors Panel
|
|
39
|
-
// action.palletName is a string type and equals to state.color which is inisde Editors Panel.
|
|
40
|
-
return { ...state, paletteName: action.paletteName }
|
|
41
|
-
case SEQUENTIAL:
|
|
42
|
-
paletteName = String(state.paletteName).endsWith('reverse') ? String(state.paletteName).substring(0, state.paletteName.length - 7) : String(state.paletteName)
|
|
43
|
-
const qualitative: string[] = palletNamesArr.filter((name: string) => name.match(qualitativeRegex) && !name.match(reverseRegex) && !name.includes('qualitative9'))
|
|
44
|
-
const sequential: string[] = palletNamesArr.filter((name: string) => !name.match(qualitativeRegex) && !name.match(reverseRegex))
|
|
45
|
-
|
|
46
|
-
return { ...state, filteredPallets: sequential, filteredQualitative: qualitative, paletteName: paletteName, isPaletteReversed: false }
|
|
47
|
-
|
|
48
|
-
case SEQUENTIAL_REVERSE:
|
|
49
|
-
paletteName = state.paletteName && String(state.paletteName).concat('reverse')
|
|
50
|
-
const qualitativeReverse: string[] = palletNamesArr.filter((name: string) => name.match(qualitativeRegex) && name.match(reverseRegex))
|
|
51
|
-
const sequentialReverse: string[] = palletNamesArr.filter((name: string) => !name.match(qualitativeRegex) && name.match(reverseRegex))
|
|
52
|
-
|
|
53
|
-
return { ...state, filteredQualitative: qualitativeReverse, filteredPallets: sequentialReverse, paletteName: paletteName, isPaletteReversed: true }
|
|
54
|
-
default:
|
|
55
|
-
return state
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
interface Keyable {
|
|
60
|
-
color: string
|
|
61
|
-
general: {
|
|
62
|
-
palette: {
|
|
63
|
-
isReversed: boolean
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function useColorPalette<T, Y extends Keyable>(colorPalettes: T, configState: Y) {
|
|
69
|
-
const [state, dispatch] = useReducer(reducer, initialState)
|
|
70
|
-
const { paletteName, isPaletteReversed, filteredPallets, filteredQualitative } = state
|
|
71
|
-
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
dispatch({ type: SEQUENTIAL, payload: colorPalettes })
|
|
74
|
-
}, [])
|
|
75
|
-
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
if (configState.general.palette.isReversed) {
|
|
78
|
-
dispatch({ type: 'SEQUENTIAL_REVERSE', payload: colorPalettes })
|
|
79
|
-
}
|
|
80
|
-
return () => dispatch({ type: 'SEQUENTIAL', payload: colorPalettes })
|
|
81
|
-
}, [configState.general.palette.isReversed, dispatch, colorPalettes])
|
|
82
|
-
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
if (configState.color) dispatch({ type: GET_PALETTE, payload: colorPalettes, paletteName: configState.color })
|
|
85
|
-
}, [dispatch, configState.color])
|
|
86
|
-
|
|
87
|
-
return { paletteName, isPaletteReversed, filteredPallets, filteredQualitative, dispatch }
|
|
88
|
-
}
|