@cdc/map 4.22.10-alpha.1 → 4.22.11

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 (47) hide show
  1. package/dist/cdcmap.js +10 -10
  2. package/examples/private/atsdr.json +19 -29
  3. package/examples/private/atsdr_new.json +1 -1
  4. package/examples/private/bubble.json +282 -284
  5. package/examples/private/city-state.json +427 -427
  6. package/examples/private/city-state2.json +433 -433
  7. package/examples/private/cty-issue.json +42765 -42768
  8. package/examples/private/default-usa.json +2 -5
  9. package/examples/private/default-world-data.json +1443 -1443
  10. package/examples/private/default.json +965 -965
  11. package/examples/private/diff.json +226 -0
  12. package/examples/private/filters.json +1 -0
  13. package/examples/private/legend-issue.json +3271 -1
  14. package/examples/private/map-issue.json +166 -0
  15. package/examples/private/map-rounding-error.json +42756 -42759
  16. package/examples/private/mdx.json +209 -209
  17. package/examples/private/monkeypox.json +375 -375
  18. package/examples/private/regions.json +51 -51
  19. package/examples/private/wcmsrd-13881-data.json +2856 -2856
  20. package/examples/private/wcmsrd-13881.json +5818 -5822
  21. package/examples/private/wcmsrd-14492-data.json +291 -291
  22. package/examples/private/wcmsrd-14492.json +103 -113
  23. package/examples/private/wcmsrd-test.json +264 -267
  24. package/examples/private/world.json +1579 -1579
  25. package/examples/private/worldmap.json +1489 -1489
  26. package/package.json +3 -3
  27. package/src/CdcMap.js +231 -315
  28. package/src/components/BubbleList.js +199 -240
  29. package/src/components/CityList.js +50 -96
  30. package/src/components/CountyMap.js +511 -600
  31. package/src/components/DataTable.js +218 -253
  32. package/src/components/EditorPanel.js +2338 -2551
  33. package/src/components/Geo.js +4 -14
  34. package/src/components/Modal.js +13 -23
  35. package/src/components/NavigationMenu.js +43 -39
  36. package/src/components/Sidebar.js +83 -93
  37. package/src/components/SingleStateMap.js +95 -151
  38. package/src/components/UsaMap.js +165 -214
  39. package/src/components/UsaRegionMap.js +122 -160
  40. package/src/components/WorldMap.js +96 -179
  41. package/src/components/ZoomableGroup.js +6 -26
  42. package/src/data/initial-state.js +1 -0
  43. package/src/hooks/useActiveElement.js +13 -13
  44. package/src/hooks/useColorPalette.ts +66 -74
  45. package/src/hooks/useZoomPan.js +22 -23
  46. package/src/index.html +1 -2
  47. package/src/scss/sidebar.scss +22 -0
@@ -1,119 +1,94 @@
1
- import React, { useEffect, memo } from 'react';
1
+ import React, { useEffect, memo } from 'react'
2
2
  /** @jsx jsx */
3
3
  import { jsx } from '@emotion/react'
4
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
5
- import { geoMercator } from "d3-geo";
6
- import { Mercator } from '@visx/geo';
7
- import { feature } from "topojson-client";
8
- import topoJSON from '../data/world-topo.json';
9
- import ZoomableGroup from './ZoomableGroup';
4
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
5
+ import { geoMercator } from 'd3-geo'
6
+ import { Mercator } from '@visx/geo'
7
+ import { feature } from 'topojson-client'
8
+ import topoJSON from '../data/world-topo.json'
9
+ import ZoomableGroup from './ZoomableGroup'
10
10
  import Geo from './Geo'
11
- import CityList from './CityList';
12
- import BubbleList from './BubbleList';
11
+ import CityList from './CityList'
12
+ import BubbleList from './BubbleList'
13
13
 
14
14
  const { features: world } = feature(topoJSON, topoJSON.objects.countries)
15
15
 
16
16
  let projection = geoMercator()
17
17
 
18
- const WorldMap = (props) => {
19
- const {
20
- state,
21
- applyTooltipsToGeo,
22
- data,
23
- geoClickHandler,
24
- applyLegendToRow,
25
- displayGeoName,
26
- supportedCountries,
27
- rebuildTooltips,
28
- setState,
29
- setRuntimeData,
30
- generateRuntimeData,
31
- setFilteredCountryCode,
32
- position,
33
- setPosition,
34
- hasZoom,
35
- handleMapAriaLabels
36
- } = props;
18
+ const WorldMap = props => {
19
+ const { state, applyTooltipsToGeo, data, geoClickHandler, applyLegendToRow, displayGeoName, supportedCountries, rebuildTooltips, setState, setRuntimeData, generateRuntimeData, setFilteredCountryCode, position, setPosition, hasZoom, handleMapAriaLabels } = props
37
20
 
38
- // TODO Refactor - state should be set together here to avoid rerenders
39
- // Resets to original data & zooms out
40
- const handleReset = (state, setState, setRuntimeData, generateRuntimeData) => {
41
- let reRun = generateRuntimeData(state)
42
- setRuntimeData(reRun)
43
- setState({
44
- ...state,
45
- focusedCountry: false,
46
- mapPosition: { coordinates: [0, 30], zoom: 1 }
47
- })
48
- setFilteredCountryCode('')
49
- }
50
- const handleZoomIn = (position, setPosition) => {
51
- if (position.zoom >= 4) return;
52
- setPosition((pos) => ({ ...pos, zoom: pos.zoom * 1.5 }));
53
- };
21
+ // TODO Refactor - state should be set together here to avoid rerenders
22
+ // Resets to original data & zooms out
23
+ const handleReset = (state, setState, setRuntimeData, generateRuntimeData) => {
24
+ let reRun = generateRuntimeData(state)
25
+ setRuntimeData(reRun)
26
+ setState({
27
+ ...state,
28
+ focusedCountry: false,
29
+ mapPosition: { coordinates: [0, 30], zoom: 1 }
30
+ })
31
+ setFilteredCountryCode('')
32
+ }
33
+ const handleZoomIn = (position, setPosition) => {
34
+ if (position.zoom >= 4) return
35
+ setPosition(pos => ({ ...pos, zoom: pos.zoom * 1.5 }))
36
+ }
54
37
 
55
- const handleZoomOut = (position, setPosition) => {
56
- if (position.zoom <= 1) return;
57
- setPosition((pos) => ({ ...pos, zoom: pos.zoom / 1.5 }));
58
- };
38
+ const handleZoomOut = (position, setPosition) => {
39
+ if (position.zoom <= 1) return
40
+ setPosition(pos => ({ ...pos, zoom: pos.zoom / 1.5 }))
41
+ }
59
42
 
60
- const ZoomControls = ({position, setPosition, state, setState, setRuntimeData, generateRuntimeData}) => (
61
- <div className="zoom-controls" data-html2canvas-ignore>
62
- <button onClick={() => handleZoomIn(position, setPosition)} aria-label="Zoom In">
63
- <svg
64
- viewBox="0 0 24 24"
65
- stroke="currentColor"
66
- strokeWidth="3"
67
- >
68
- <line x1="12" y1="5" x2="12" y2="19" />
69
- <line x1="5" y1="12" x2="19" y2="12" />
70
- </svg>
71
- </button>
72
- <button onClick={() => handleZoomOut(position, setPosition)} aria-label="Zoom Out">
73
- <svg
74
- viewBox="0 0 24 24"
75
- stroke="currentColor"
76
- strokeWidth="3"
77
- >
78
- <line x1="5" y1="12" x2="19" y2="12" />
79
- </svg>
80
- </button>
81
- {state.general.type === 'bubble' &&
82
- <button onClick={() => handleReset(state, setState, setRuntimeData, generateRuntimeData)} className="reset" aria-label="Reset Zoom and Map Filters">
83
- Reset Filters
43
+ const ZoomControls = ({ position, setPosition, state, setState, setRuntimeData, generateRuntimeData }) => (
44
+ <div className='zoom-controls' data-html2canvas-ignore>
45
+ <button onClick={() => handleZoomIn(position, setPosition)} aria-label='Zoom In'>
46
+ <svg viewBox='0 0 24 24' stroke='currentColor' strokeWidth='3'>
47
+ <line x1='12' y1='5' x2='12' y2='19' />
48
+ <line x1='5' y1='12' x2='19' y2='12' />
49
+ </svg>
84
50
  </button>
85
- }
86
- </div>
87
- );
51
+ <button onClick={() => handleZoomOut(position, setPosition)} aria-label='Zoom Out'>
52
+ <svg viewBox='0 0 24 24' stroke='currentColor' strokeWidth='3'>
53
+ <line x1='5' y1='12' x2='19' y2='12' />
54
+ </svg>
55
+ </button>
56
+ {state.general.type === 'bubble' && (
57
+ <button onClick={() => handleReset(state, setState, setRuntimeData, generateRuntimeData)} className='reset' aria-label='Reset Zoom and Map Filters'>
58
+ Reset Filters
59
+ </button>
60
+ )}
61
+ </div>
62
+ )
88
63
 
89
64
  // TODO Refactor - state should be set together here to avoid rerenders
90
65
  const handleCircleClick = (country, state, setState, setRuntimeData, generateRuntimeData) => {
91
- if(!state.general.allowMapZoom) return;
66
+ if (!state.general.allowMapZoom) return
92
67
  let newRuntimeData = state.data.filter(item => item[state.columns.geo.name] === country[state.columns.geo.name])
93
68
  setFilteredCountryCode(newRuntimeData[0].uid)
94
69
  }
95
70
 
96
- useEffect(() => rebuildTooltips());
71
+ useEffect(() => rebuildTooltips())
97
72
 
98
- const handleMoveEnd = (position) => {
99
- setPosition(position);
100
- };
73
+ const handleMoveEnd = position => {
74
+ setPosition(position)
75
+ }
101
76
 
102
- const constructGeoJsx = (geographies) => {
77
+ const constructGeoJsx = geographies => {
103
78
  const geosJsx = geographies.map(({ feature: geo, path }, i) => {
104
79
  const geoKey = geo.properties.iso
105
80
 
106
- if(!geoKey) return
81
+ if (!geoKey) return
107
82
 
108
- const geoData = data[geoKey];
83
+ const geoData = data[geoKey]
109
84
 
110
- const geoDisplayName = displayGeoName(supportedCountries[geoKey][0]);
85
+ const geoDisplayName = displayGeoName(supportedCountries[geoKey][0])
111
86
 
112
- let legendColors;
87
+ let legendColors
113
88
 
114
89
  // Once we receive data for this geographic item, setup variables.
115
90
  if (geoData !== undefined) {
116
- legendColors = applyLegendToRow(geoData);
91
+ legendColors = applyLegendToRow(geoData)
117
92
  }
118
93
 
119
94
  const geoStrokeColor = state.general.geoBorderColor === 'darkGray' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255,255,255,0.7)'
@@ -123,65 +98,44 @@ const ZoomControls = ({position, setPosition, state, setState, setRuntimeData, g
123
98
  cursor: 'default'
124
99
  }
125
100
 
126
- const strokeWidth = .9
101
+ const strokeWidth = 0.9
127
102
 
128
103
  // If a legend applies, return it with appropriate information.
129
104
  if (legendColors && legendColors[0] !== '#000000' && state.general.type !== 'bubble') {
130
- const tooltip = applyTooltipsToGeo(geoDisplayName, geoData);
131
-
132
- styles = {
133
- ...styles,
134
- fill: legendColors[0],
135
- cursor: 'default',
136
- '&:hover': {
137
- fill: legendColors[1]
138
- },
139
- '&:active': {
140
- fill: legendColors[2],
141
- },
142
- };
105
+ const tooltip = applyTooltipsToGeo(geoDisplayName, geoData)
106
+
107
+ styles = {
108
+ ...styles,
109
+ fill: legendColors[0],
110
+ cursor: 'default',
111
+ '&:hover': {
112
+ fill: legendColors[1]
113
+ },
114
+ '&:active': {
115
+ fill: legendColors[2]
116
+ }
117
+ }
143
118
 
144
119
  // When to add pointer cursor
145
120
  if ((state.columns.navigate && geoData[state.columns.navigate.name]) || state.tooltips.appearanceType === 'click') {
146
121
  styles.cursor = 'pointer'
147
122
  }
148
123
 
149
- return (
150
- <Geo
151
- key={i + '-geo'}
152
- css={styles}
153
- data-for="tooltip"
154
- data-tip={tooltip}
155
- path={path}
156
- stroke={geoStrokeColor}
157
- strokeWidth={strokeWidth}
158
- onClick={() => geoClickHandler(geoDisplayName, geoData)}
159
- />
160
- )
124
+ return <Geo key={i + '-geo'} css={styles} data-for='tooltip' data-tip={tooltip} path={path} stroke={geoStrokeColor} strokeWidth={strokeWidth} onClick={() => geoClickHandler(geoDisplayName, geoData)} />
161
125
  }
162
126
 
163
127
  // Default return state, just geo with no additional information
164
128
  return <Geo key={i + '-geo'} stroke={geoStrokeColor} strokeWidth={strokeWidth} css={styles} path={path} />
165
- });
129
+ })
166
130
 
167
131
  // Cities
168
- geosJsx.push(<CityList
169
- projection={projection}
170
- key="cities"
171
- data={data}
172
- state={state}
173
- geoClickHandler={geoClickHandler}
174
- applyTooltipsToGeo={applyTooltipsToGeo}
175
- displayGeoName={displayGeoName}
176
- applyLegendToRow={applyLegendToRow}
177
- isGeoCodeMap={state.general.type === 'us-geocode'}
178
- />)
132
+ geosJsx.push(<CityList projection={projection} key='cities' data={data} state={state} geoClickHandler={geoClickHandler} applyTooltipsToGeo={applyTooltipsToGeo} displayGeoName={displayGeoName} applyLegendToRow={applyLegendToRow} isGeoCodeMap={state.general.type === 'us-geocode'} />)
179
133
 
180
134
  // Bubbles
181
- if(state.general.type === 'bubble') {
135
+ if (state.general.type === 'bubble') {
182
136
  geosJsx.push(
183
137
  <BubbleList
184
- key="bubbles"
138
+ key='bubbles'
185
139
  data={state.data}
186
140
  runtimeData={data}
187
141
  state={state}
@@ -189,70 +143,33 @@ const ZoomControls = ({position, setPosition, state, setState, setRuntimeData, g
189
143
  applyLegendToRow={applyLegendToRow}
190
144
  applyTooltipsToGeo={applyTooltipsToGeo}
191
145
  displayGeoName={displayGeoName}
192
- handleCircleClick={(country) => handleCircleClick(country, state, setState, setRuntimeData, generateRuntimeData) }
146
+ handleCircleClick={country => handleCircleClick(country, state, setState, setRuntimeData, generateRuntimeData)}
193
147
  />
194
148
  )
195
149
  }
196
150
 
197
- return geosJsx;
198
- };
151
+ return geosJsx
152
+ }
199
153
 
200
154
  return (
201
- <ErrorBoundary component="WorldMap">
155
+ <ErrorBoundary component='WorldMap'>
202
156
  {hasZoom ? (
203
- <svg
204
- viewBox="0 0 880 500"
205
- role="img"
206
- aria-label={handleMapAriaLabels(state)}
207
- >
208
- <rect height={500} width={880} onClick={() => handleReset(state, setState, setRuntimeData, generateRuntimeData)} fill="white"/>
209
- <ZoomableGroup
210
- zoom={position.zoom}
211
- center={position.coordinates}
212
- onMoveEnd={handleMoveEnd}
213
- maxZoom={4}
214
- projection={projection}
215
- width={880}
216
- height={500}
217
- >
218
- <Mercator
219
- data={world}
220
- >
221
- {({ features }) => constructGeoJsx(features)}
222
- </Mercator>
157
+ <svg viewBox='0 0 880 500' role='img' aria-label={handleMapAriaLabels(state)}>
158
+ <rect height={500} width={880} onClick={() => handleReset(state, setState, setRuntimeData, generateRuntimeData)} fill='white' />
159
+ <ZoomableGroup zoom={position.zoom} center={position.coordinates} onMoveEnd={handleMoveEnd} maxZoom={4} projection={projection} width={880} height={500}>
160
+ <Mercator data={world}>{({ features }) => constructGeoJsx(features)}</Mercator>
223
161
  </ZoomableGroup>
224
162
  </svg>
225
- ) :
226
- <svg viewBox="0 0 880 500">
227
- <ZoomableGroup
228
- zoom={1}
229
- center={position.coordinates}
230
- onMoveEnd={handleMoveEnd}
231
- maxZoom={0}
232
- projection={projection}
233
- width={880}
234
- height={500}
235
- >
236
- <Mercator
237
- data={world}
238
- >
239
- {({ features }) => constructGeoJsx(features)}
240
- </Mercator>
163
+ ) : (
164
+ <svg viewBox='0 0 880 500'>
165
+ <ZoomableGroup zoom={1} center={position.coordinates} onMoveEnd={handleMoveEnd} maxZoom={0} projection={projection} width={880} height={500}>
166
+ <Mercator data={world}>{({ features }) => constructGeoJsx(features)}</Mercator>
241
167
  </ZoomableGroup>
242
168
  </svg>
243
- }
244
- {(state.general.type === 'data' || state.general.type === 'bubble' && hasZoom) &&
245
- <ZoomControls
246
- position={position}
247
- setPosition={setPosition}
248
- setRuntimeData={setRuntimeData}
249
- state={state}
250
- setState={setState}
251
- generateRuntimeData={generateRuntimeData} />
252
- }
253
-
169
+ )}
170
+ {(state.general.type === 'data' || (state.general.type === 'bubble' && hasZoom)) && <ZoomControls position={position} setPosition={setPosition} setRuntimeData={setRuntimeData} state={state} setState={setState} generateRuntimeData={generateRuntimeData} />}
254
171
  </ErrorBoundary>
255
- );
256
- };
172
+ )
173
+ }
257
174
 
258
175
  export default memo(WorldMap)
@@ -1,28 +1,8 @@
1
+ import React, { useContext } from 'react'
2
+ import useZoomPan from '../hooks/useZoomPan'
1
3
 
2
- import React, { useContext } from "react"
3
- import useZoomPan from "../hooks/useZoomPan"
4
-
5
- const ZoomableGroup = ({
6
- center = [0, 0],
7
- zoom = 1,
8
- minZoom = 1,
9
- maxZoom = 8,
10
- translateExtent,
11
- filterZoomEvent,
12
- onMoveStart,
13
- onMove,
14
- onMoveEnd,
15
- className,
16
- projection,
17
- width,
18
- height,
19
- ...restProps
20
- }) => {
21
-
22
- const {
23
- mapRef,
24
- transformString,
25
- } = useZoomPan({
4
+ const ZoomableGroup = ({ center = [0, 0], zoom = 1, minZoom = 1, maxZoom = 8, translateExtent, filterZoomEvent, onMoveStart, onMove, onMoveEnd, className, projection, width, height, ...restProps }) => {
5
+ const { mapRef, transformString } = useZoomPan({
26
6
  center,
27
7
  filterZoomEvent,
28
8
  onMoveStart,
@@ -38,10 +18,10 @@ const ZoomableGroup = ({
38
18
 
39
19
  return (
40
20
  <g ref={mapRef}>
41
- <rect width={width} height={height} fill="transparent" />
21
+ <rect width={width} height={height} fill='transparent' />
42
22
  <g transform={transformString} {...restProps} />
43
23
  </g>
44
24
  )
45
25
  }
46
26
 
47
- export default ZoomableGroup
27
+ export default ZoomableGroup
@@ -51,6 +51,7 @@ export default {
51
51
  specialClasses: [],
52
52
  unified: false,
53
53
  singleColumn: false,
54
+ singleRow: false,
54
55
  dynamicDescription: false,
55
56
  type: "equalnumber",
56
57
  numberOfItems: 3,
@@ -1,19 +1,19 @@
1
- import {useState, useEffect} from 'react'
1
+ import { useState, useEffect } from 'react'
2
2
  // Use for accessibility testing
3
3
  const useActiveElement = () => {
4
- const [active, setActive] = useState(document.activeElement);
4
+ const [active, setActive] = useState(document.activeElement)
5
5
 
6
- const handleFocusIn = (e) => {
7
- setActive(document.activeElement);
8
- }
6
+ const handleFocusIn = e => {
7
+ setActive(document.activeElement)
8
+ }
9
9
 
10
- useEffect(() => {
11
- document.addEventListener('focusin', handleFocusIn)
12
- return () => {
13
- document.removeEventListener('focusin', handleFocusIn)
14
- };
15
- }, [])
10
+ useEffect(() => {
11
+ document.addEventListener('focusin', handleFocusIn)
12
+ return () => {
13
+ document.removeEventListener('focusin', handleFocusIn)
14
+ }
15
+ }, [])
16
16
 
17
- return active;
17
+ return active
18
18
  }
19
- export default useActiveElement;
19
+ export default useActiveElement
@@ -1,96 +1,88 @@
1
- import { useEffect, useReducer } from 'react';
1
+ import { useEffect, useReducer } from 'react'
2
2
 
3
- // constants
4
- const SEQUENTIAL = 'SEQUENTIAL';
5
- const SEQUENTIAL_REVERSE = 'SEQUENTIAL_REVERSE';
6
- export const GET_PALETTE = 'GET_PALETTE';
3
+ // constants
4
+ const SEQUENTIAL = 'SEQUENTIAL'
5
+ const SEQUENTIAL_REVERSE = 'SEQUENTIAL_REVERSE'
6
+ export const GET_PALETTE = 'GET_PALETTE'
7
7
 
8
-
9
- // types & interfaces
8
+ // types & interfaces
10
9
  interface State {
11
- readonly filteredPallets:string[]
12
- readonly filteredQualitative:string[]
13
- readonly isPaletteReversed:boolean;
14
- paletteName:string|undefined
15
- }
16
- interface Action<Palettes> {
17
- type:
18
- | 'SEQUENTIAL'
19
- | 'SEQUENTIAL_REVERSE'
20
- | 'GET_PALETTE'
21
- payload: Palettes;
22
- paletteName?:string
23
- };
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
+ }
24
20
 
25
21
  // create initial state
26
- const initialState:State = {
27
- filteredPallets: [],
28
- isPaletteReversed:false,
29
- filteredQualitative: [],
30
- paletteName:undefined
31
- };
22
+ const initialState: State = {
23
+ filteredPallets: [],
24
+ isPaletteReversed: false,
25
+ filteredQualitative: [],
26
+ paletteName: undefined
27
+ }
32
28
 
33
29
  // create reducer function to handle multiple states & manupilate with each state
34
- function reducer<T> (state:State,action:Action<T>):State{ // <T> refers to generic type
35
- const palletNamesArr:string[] = Object.keys(action.payload); // action.payload === colorPalettes object
36
- let reverseRegex = new RegExp('reverse$'); // matches a string that ends in with "reverse".
37
- let qualitativeRegex = new RegExp('^qualitative'); //matches any string that starts with "qualitative".
38
- let paletteName:string ='';
39
- switch(action.type){
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) {
40
37
  case GET_PALETTE:
41
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
42
39
  // action.palletName is a string type and equals to state.color which is inisde Editors Panel.
43
- return {...state,paletteName:action.paletteName}
44
- case SEQUENTIAL:
45
- paletteName = String(state.paletteName).endsWith('reverse') ? String(state.paletteName).substring(0,state.paletteName.length-7):String(state.paletteName)
46
- const qualitative :string[]= palletNamesArr.filter((name: string) => name.match(qualitativeRegex) && (!name.match(reverseRegex) && !name.includes('qualitative9')));
47
- const sequential:string[] = palletNamesArr.filter((name: string) => !name.match(qualitativeRegex) && !name.match(reverseRegex));
48
-
49
- return { ...state, filteredPallets: sequential,filteredQualitative:qualitative, paletteName:paletteName,isPaletteReversed:false};
50
-
51
- case SEQUENTIAL_REVERSE:
52
- paletteName= state.paletteName && String(state.paletteName).concat('reverse');
53
- const qualitativeReverse:string[] = palletNamesArr.filter((name: string) => name.match(qualitativeRegex) && name.match(reverseRegex));
54
- const sequentialReverse:string[] = palletNamesArr.filter((name: string) => !name.match(qualitativeRegex) && name.match(reverseRegex));
55
-
56
- return { ...state, filteredQualitative:qualitativeReverse, filteredPallets: sequentialReverse ,paletteName:paletteName,isPaletteReversed:true};
57
- default : return state;
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
58
56
  }
59
- };
57
+ }
60
58
 
61
59
  interface Keyable {
62
- color:string
63
- general:{
64
- palette:{
65
- isReversed:boolean
60
+ color: string
61
+ general: {
62
+ palette: {
63
+ isReversed: boolean
66
64
  }
67
65
  }
68
66
  }
69
67
 
70
- export function useColorPalette<T,Y extends Keyable>(colorPalettes:T,configState:Y){
71
- const [state, dispatch] = useReducer(reducer, initialState);
72
- const {paletteName,isPaletteReversed,filteredPallets,filteredQualitative} = state
73
-
74
-
75
-
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
76
71
 
77
72
  useEffect(() => {
78
- dispatch({ type: SEQUENTIAL, payload: colorPalettes });
79
- }, []);
80
-
81
-
82
- useEffect(()=>{
83
- if(configState.general.palette.isReversed){
84
- dispatch({ type: "SEQUENTIAL_REVERSE", payload: colorPalettes });
85
- }
86
- return ()=> dispatch({ type: "SEQUENTIAL", payload: colorPalettes });
87
-
88
- },[configState.general.palette.isReversed,dispatch,colorPalettes])
73
+ dispatch({ type: SEQUENTIAL, payload: colorPalettes })
74
+ }, [])
89
75
 
90
- useEffect(()=>{
91
- if(configState.color) dispatch({type:GET_PALETTE,payload:colorPalettes,paletteName:configState.color})
92
- },[dispatch,configState.color])
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])
93
82
 
83
+ useEffect(() => {
84
+ if (configState.color) dispatch({ type: GET_PALETTE, payload: colorPalettes, paletteName: configState.color })
85
+ }, [dispatch, configState.color])
94
86
 
95
- return {paletteName,isPaletteReversed,filteredPallets,filteredQualitative,dispatch}
96
- }
87
+ return { paletteName, isPaletteReversed, filteredPallets, filteredQualitative, dispatch }
88
+ }