@cdc/waffle-chart 4.24.2 → 4.24.4

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/index.html CHANGED
@@ -4,18 +4,25 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
6
6
  <style>
7
+ .type-waffle-chart {
8
+ min-height: 100vh;
9
+ }
10
+
7
11
  body {
8
12
  /* max-width: 1000px; */
9
13
  margin: 0 auto !important;
10
14
  display: flex;
11
15
  flex-direction: column;
12
16
  justify-content: center;
17
+ border-top: none !important;
13
18
  }
14
19
 
15
20
  .react-container + .react-container {
16
21
  margin-top: 3rem;
17
22
  }
18
23
  </style>
24
+ <link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/contrib/libs/bootstrap/latest/css/bootstrap.min.css?_=39423" />
25
+ <link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/4.0/assets/css/app.min.css?_=39423" />
19
26
  </head>
20
27
  <body>
21
28
  <!-- Original -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/waffle-chart",
3
- "version": "4.24.2",
3
+ "version": "4.24.4",
4
4
  "description": "React component for displaying a single piece of data in a card module",
5
5
  "moduleName": "CdcWaffleChart",
6
6
  "main": "dist/cdcwafflechart",
@@ -26,7 +26,7 @@
26
26
  "license": "Apache-2.0",
27
27
  "homepage": "https://github.com/CDCgov/cdc-open-viz#readme",
28
28
  "dependencies": {
29
- "@cdc/core": "^4.24.2",
29
+ "@cdc/core": "^4.24.4",
30
30
  "@visx/group": "^3.0.0",
31
31
  "@visx/scale": "^3.0.0",
32
32
  "@visx/shape": "^3.0.0",
@@ -41,5 +41,5 @@
41
41
  "react": "^18.2.0",
42
42
  "react-dom": "^18.2.0"
43
43
  },
44
- "gitHead": "edde49c96dee146de5e3a4537880b1bcf4dbee08"
44
+ "gitHead": "1843b4632140d582af6a87606374cbd4fe25ad5c"
45
45
  }
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect, useReducer } from 'react'
1
+ import React, { useCallback, useEffect, useReducer, useState } from 'react'
2
2
 
3
3
  // visx
4
4
  import { Circle, Bar } from '@visx/shape'
@@ -27,6 +27,7 @@ import useDataVizClasses from '@cdc/core/helpers/useDataVizClasses'
27
27
 
28
28
  import './scss/main.scss'
29
29
  import Title from '@cdc/core/components/ui/Title'
30
+ import Layout from '@cdc/core/components/Layout'
30
31
 
31
32
  type CdcWaffleChartProps = {
32
33
  configUrl?: string
@@ -37,24 +38,9 @@ type CdcWaffleChartProps = {
37
38
  setConfig?: () => void
38
39
  }
39
40
 
40
- const WaffleChart = ({ config, isEditor, link = '' }) => {
41
+ const WaffleChart = ({ config, isEditor, link = '', showConfigConfirm, updateConfig }) => {
41
42
  const { title, theme, shape, nodeWidth, nodeSpacer, prefix, suffix, subtext, content, orientation, filters, dataColumn, dataFunction, dataConditionalColumn, dataConditionalOperator, dataConditionalComparate, customDenom, dataDenom, dataDenomColumn, dataDenomFunction, roundToPlace } = config
42
43
 
43
- const handleWaffleChartAriaLabel = (state, testing = false): string => {
44
- // eslint-disable-next-line no-console
45
- if (testing) console.log(`handleWaffleChartAriaLabels Testing On:`, state)
46
- try {
47
- let ariaLabel = 'Waffle chart'
48
- if (state.title) {
49
- ariaLabel += ` with the title: ${state.title}`
50
- }
51
- return ariaLabel
52
- } catch (e) {
53
- // eslint-disable-next-line no-console
54
- console.error(e.message)
55
- }
56
- }
57
-
58
44
  const gaugeColor = config.visual.colors[config.theme]
59
45
  let dataFontSize = config.fontSize ? { fontSize: config.fontSize + 'px' } : null
60
46
 
@@ -279,58 +265,90 @@ const WaffleChart = ({ config, isEditor, link = '' }) => {
279
265
  range: [0, config.gauge.width]
280
266
  })
281
267
 
268
+ const Error = ({ config, updateConfig }) => {
269
+ return (
270
+ <section className='waiting'>
271
+ <section className='waiting-container'>
272
+ <h3>Error With Configuration</h3>
273
+ <p>{config.runtime.editorErrorMessage}</p>
274
+ </section>
275
+ </section>
276
+ )
277
+ }
278
+
279
+ const Confirm = ({ updateConfig, config }) => {
280
+ const confirmDone = e => {
281
+ e.preventDefault()
282
+ let newConfig = { ...config }
283
+ delete newConfig.newViz
284
+ updateConfig(newConfig)
285
+ }
286
+
287
+ return (
288
+ <section className='waiting'>
289
+ <section className='waiting-container'>
290
+ <h3>Finish Configuring</h3>
291
+ <p>Set all required options to the left and confirm below to display a preview of the chart.</p>
292
+ <button className='btn' style={{ margin: '1em auto' }} onClick={confirmDone}>
293
+ I'm Done
294
+ </button>
295
+ </section>
296
+ </section>
297
+ )
298
+ }
299
+
282
300
  return (
283
- <div className={innerContainerClasses.join(' ')}>
284
- <>
285
- <Title title={title} config={config} classes={['chart-title', `${config.theme}`, 'mb-0']} />
286
- <div className={contentClasses.join(' ')}>
287
- <div className='cove-component__content-wrap'>
288
- {config.visualizationType === 'Gauge' && (
289
- <div className={`cove-gauge-chart${config.overallFontSize ? ' font-' + config.overallFontSize : ''}`}>
290
- <div className='cove-gauge-chart__chart'>
291
- <div className='cove-waffle-chart__data--primary' style={dataFontSize}>
292
- {prefix ? prefix : ' '}
293
- {config.showPercent ? dataPercentage : waffleNumerator}
294
- {suffix ? suffix + ' ' : ' '} {config.valueDescription} {config.showDenominator && waffleDenominator ? waffleDenominator : ' '}
295
- </div>
296
- <div className='cove-waffle-chart__data--text'>{parse(content)}</div>
297
- <svg height={config.gauge.height} width={'100%'}>
298
- <Group>
299
- <foreignObject style={{ border: '1px solid black' }} x={0} y={0} width={config.gauge.width} height={config.gauge.height} fill='#fff' />
300
- <Bar x={0} y={0} width={xScale(waffleNumerator)} height={config.gauge.height} fill={gaugeColor} />
301
- </Group>
302
- </svg>
303
- <div className={'cove-waffle-chart__subtext subtext'}>{parse(subtext)}</div>
301
+ <div className='cove-component__content'>
302
+ <Title title={title} config={config} classes={['chart-title', `${config.theme}`, 'mb-0']} />
303
+ <div className={contentClasses.join(' ')}>
304
+ {!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error updateConfig={updateConfig} config={config} />}
305
+ {config.newViz && showConfigConfirm && <Confirm updateConfig={updateConfig} config={config} />}
306
+ <div className='cove-component__content-wrap'>
307
+ {config.visualizationType === 'Gauge' && (
308
+ <div className={`cove-gauge-chart${config.overallFontSize ? ' font-' + config.overallFontSize : ''}`}>
309
+ <div className='cove-gauge-chart__chart'>
310
+ <div className='cove-waffle-chart__data--primary' style={dataFontSize}>
311
+ {prefix ? prefix : ' '}
312
+ {config.showPercent ? dataPercentage : waffleNumerator}
313
+ {suffix ? suffix + ' ' : ' '} {config.valueDescription} {config.showDenominator && waffleDenominator ? waffleDenominator : ' '}
304
314
  </div>
315
+ <div className='cove-waffle-chart__data--text'>{parse(content)}</div>
316
+ <svg height={config.gauge.height} width={'100%'}>
317
+ <Group>
318
+ <foreignObject style={{ border: '1px solid black' }} x={0} y={0} width={config.gauge.width} height={config.gauge.height} fill='#fff' />
319
+ <Bar x={0} y={0} width={xScale(waffleNumerator)} height={config.gauge.height} fill={gaugeColor} />
320
+ </Group>
321
+ </svg>
322
+ <div className={'cove-waffle-chart__subtext subtext'}>{parse(subtext)}</div>
305
323
  </div>
306
- )}
307
- {config.visualizationType !== 'Gauge' && (
308
- <div className={`cove-waffle-chart${orientation === 'vertical' ? ' cove-waffle-chart--verical' : ''}${config.overallFontSize ? ' font-' + config.overallFontSize : ''}`}>
309
- <div className='cove-waffle-chart__chart' style={{ width: setRatio() }}>
310
- <svg width={setRatio()} height={setRatio()} role='img' aria-label={handleWaffleChartAriaLabel(config)} tabIndex={0}>
311
- <Group>{buildWaffle()}</Group>
312
- </svg>
313
- </div>
314
- {(dataPercentage || content) && (
315
- <div className='cove-waffle-chart__data'>
316
- {dataPercentage && (
317
- <div className='cove-waffle-chart__data--primary' style={dataFontSize}>
318
- {prefix ? prefix : null}
319
- {dataPercentage}
320
- {suffix ? suffix : null}
321
- </div>
322
- )}
323
- <div className='cove-waffle-chart__data--text'>{parse(content)}</div>
324
-
325
- {subtext && <div className='cove-waffle-chart__subtext subtext'>{parse(subtext)}</div>}
326
- </div>
327
- )}
324
+ </div>
325
+ )}
326
+ {config.visualizationType !== 'Gauge' && (
327
+ <div className={`cove-waffle-chart${orientation === 'vertical' ? ' cove-waffle-chart--verical' : ''}${config.overallFontSize ? ' font-' + config.overallFontSize : ''}`}>
328
+ <div className='cove-waffle-chart__chart' style={{ width: setRatio() }}>
329
+ <svg width={setRatio()} height={setRatio()}>
330
+ <Group>{buildWaffle()}</Group>
331
+ </svg>
328
332
  </div>
329
- )}
330
- </div>
333
+ {(dataPercentage || content) && (
334
+ <div className='cove-waffle-chart__data'>
335
+ {dataPercentage && (
336
+ <div className='cove-waffle-chart__data--primary' style={dataFontSize}>
337
+ {prefix ? prefix : null}
338
+ {dataPercentage}
339
+ {suffix ? suffix : null}
340
+ </div>
341
+ )}
342
+ <div className='cove-waffle-chart__data--text'>{parse(content)}</div>
343
+
344
+ {subtext && <div className='cove-waffle-chart__subtext subtext'>{parse(subtext)}</div>}
345
+ </div>
346
+ )}
347
+ </div>
348
+ )}
331
349
  </div>
332
- {link && link}
333
- </>
350
+ </div>
351
+ {link && link}
334
352
  </div>
335
353
  )
336
354
  }
@@ -339,6 +357,7 @@ const CdcWaffleChart = ({ configUrl, config: configObj, isDashboard = false, isE
339
357
  // Default States
340
358
  const [state, dispatch] = useReducer(chartReducer, { config: configObj ?? defaults, loading: true, preview: false, viewport: 'lg', coveLoadedHasRan: false, container: null })
341
359
  const { loading, config, viewport: currentViewport, coveLoadedHasRan, container } = state
360
+ const [showConfigConfirm, setShowConfigConfirm] = useState(false)
342
361
 
343
362
  // Default Functions
344
363
  const updateConfig = newConfig => {
@@ -417,31 +436,27 @@ const CdcWaffleChart = ({ configUrl, config: configObj, isDashboard = false, isE
417
436
  let content = <Loading />
418
437
 
419
438
  if (loading === false) {
420
- let classNames = ['cove', 'cdc-open-viz-module', 'type-waffle-chart', currentViewport, config.theme, 'font-' + config.overallFontSize]
421
-
422
- if (isEditor) {
423
- classNames.push('is-editor')
424
- }
425
-
426
- let bodyClasses = ['cove-component', 'waffle-chart']
427
-
428
439
  let body = (
429
- <div className={`${bodyClasses.join(' ')}`} ref={outerContainerRef}>
430
- <WaffleChart config={config} isEditor={isEditor} />
431
- </div>
440
+ <Layout.Responsive isEditor={isEditor}>
441
+ <WaffleChart config={config} isEditor={isEditor} showConfigConfirm={showConfigConfirm} updateConfig={updateConfig} />
442
+ </Layout.Responsive>
432
443
  )
433
444
 
434
445
  content = (
435
- <div className={classNames.join(' ')}>
436
- {isEditor && <EditorPanel>{body}</EditorPanel>}
446
+ <>
447
+ {isEditor && <EditorPanel showConfigConfirm={showConfigConfirm}>{body}</EditorPanel>}
437
448
  {!isEditor && body}
438
- </div>
449
+ </>
439
450
  )
440
451
  }
441
452
 
442
453
  return (
443
454
  <ErrorBoundary component='WaffleChart'>
444
- <ConfigContext.Provider value={{ config, updateConfig, loading, data: config.data, setParentConfig, isDashboard, outerContainerRef }}>{content}</ConfigContext.Provider>
455
+ <ConfigContext.Provider value={{ config, updateConfig, loading, data: config.data, setParentConfig, isDashboard, outerContainerRef }}>
456
+ <Layout.VisualizationWrapper config={config} isEditor={isEditor} ref={outerContainerRef} showEditorPanel={config?.showEditorPanel}>
457
+ {content}
458
+ </Layout.VisualizationWrapper>
459
+ </ConfigContext.Provider>
445
460
  </ErrorBoundary>
446
461
  )
447
462
  }
@@ -11,6 +11,8 @@ import Tooltip from '@cdc/core/components/ui/Tooltip'
11
11
  import InputText from '@cdc/core/components/inputs/InputText'
12
12
  import InputSelect from '@cdc/core/components/inputs/InputSelect'
13
13
  import InputCheckbox from '@cdc/core/components/inputs/InputCheckbox'
14
+ import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
15
+ import Layout from '@cdc/core/components/Layout'
14
16
 
15
17
  import '@cdc/core/styles/v2/components/editor.scss'
16
18
  import WarningImage from '../images/warning.svg'
@@ -37,42 +39,11 @@ const CheckBox = memo(({ label, value, fieldName, section = null, subsection = n
37
39
 
38
40
  const EditorPanel = memo(props => {
39
41
  const { config, updateConfig, loading, data, setParentConfig, isDashboard } = useContext(ConfigContext)
40
-
42
+ const { showConfigConfirm } = props
41
43
  const [displayPanel, setDisplayPanel] = useState(true)
42
- const [showConfigConfirm, setShowConfigConfirm] = useState(false)
43
44
  const inputSelectStyle = condition => (condition ? { backgroundColor: '#ffd2d2', color: '#d8000c' } : {})
44
45
 
45
- const updateField = (section, subsection, fieldName, newValue) => {
46
- // Top level
47
- if (null === section && null === subsection) {
48
- let updatedConfig = { ...config, [fieldName]: newValue }
49
-
50
- if ('filterColumn' === fieldName) {
51
- updatedConfig.filterValue = ''
52
- }
53
-
54
- updateConfig(updatedConfig)
55
- return
56
- }
57
-
58
- const isArray = Array.isArray(config[section])
59
-
60
- let sectionValue = isArray ? [...config[section], newValue] : { ...config[section], [fieldName]: newValue }
61
-
62
- if (null !== subsection) {
63
- if (isArray) {
64
- sectionValue = [...config[section]]
65
- sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue }
66
- } else if (typeof newValue === 'string') {
67
- sectionValue[subsection] = newValue
68
- } else {
69
- sectionValue = { ...config[section], [subsection]: { ...config[section][subsection], [fieldName]: newValue } }
70
- }
71
- }
72
- let updatedConfig = { ...config, [section]: sectionValue }
73
-
74
- updateConfig(updatedConfig)
75
- }
46
+ const updateField = updateFieldFactory(config, updateConfig, true)
76
47
 
77
48
  useEffect(() => {
78
49
  // Pass up to Editor if needed
@@ -109,6 +80,10 @@ const EditorPanel = memo(props => {
109
80
 
110
81
  const onBackClick = () => {
111
82
  setDisplayPanel(!displayPanel)
83
+ updateConfig({
84
+ ...config,
85
+ showEditorPanel: !displayPanel
86
+ })
112
87
 
113
88
  // if (isDashboard) {
114
89
  // updateConfig({ ...config, editing: false })
@@ -117,38 +92,6 @@ const EditorPanel = memo(props => {
117
92
  // }
118
93
  }
119
94
 
120
- const Error = () => {
121
- return (
122
- <section className='waiting'>
123
- <section className='waiting-container'>
124
- <h3>Error With Configuration</h3>
125
- <p>{config.runtime.editorErrorMessage}</p>
126
- </section>
127
- </section>
128
- )
129
- }
130
-
131
- const Confirm = () => {
132
- const confirmDone = e => {
133
- e.preventDefault()
134
- let newConfig = { ...config }
135
- delete newConfig.newViz
136
- updateConfig(newConfig)
137
- }
138
-
139
- return (
140
- <section className='waiting'>
141
- <section className='waiting-container'>
142
- <h3>Finish Configuring</h3>
143
- <p>Set all required options to the left and confirm below to display a preview of the chart.</p>
144
- <button className='btn' style={{ margin: '1em auto' }} onClick={confirmDone}>
145
- I'm Done
146
- </button>
147
- </section>
148
- </section>
149
- )
150
- }
151
-
152
95
  const convertStateToConfig = () => {
153
96
  let strippedState = JSON.parse(JSON.stringify(config))
154
97
  delete strippedState.newViz
@@ -456,20 +399,12 @@ const EditorPanel = memo(props => {
456
399
 
457
400
  return (
458
401
  <ErrorBoundary component='EditorPanel'>
459
- <div className='cove-editor'>
460
- {!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error />}
461
- {config.newViz && showConfigConfirm && <Confirm />}
462
- <button className={`cove-editor--toggle` + (!displayPanel ? ` collapsed` : ``)} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick} />
463
- <section className={`cove-editor__panel` + (displayPanel ? `` : ' hidden')}>
464
- <div className='cove-editor__panel-container'>
465
- <h2 className='cove-editor__heading'>Configure Chart</h2>
466
- <section className='cove-editor__content'>{editorContent}</section>
467
- </div>
468
- </section>
469
- <div className='cove-editor__content'>
470
- <div className='cove-editor__content-wrap'>{props.children}</div>
471
- </div>
472
- </div>
402
+ <>
403
+ <Layout.Sidebar displayPanel={displayPanel} onBackClick={onBackClick} isDashboard={isDashboard} title='Configure Waffle Chart' showEditorPanel={displayPanel}>
404
+ {editorContent}
405
+ </Layout.Sidebar>
406
+ {props.children}
407
+ </>
473
408
  </ErrorBoundary>
474
409
  )
475
410
  })
@@ -1,6 +1,6 @@
1
- @import '@cdc/core/styles/v2/components/input';
2
- @import '@cdc/core/styles/v2/main';
3
1
  @import '@cdc/core/styles/base';
2
+ @import '@cdc/core/styles/heading-colors';
3
+ @import '@cdc/core/styles/v2/themes/color-definitions';
4
4
  @import 'waffle-chart';
5
5
 
6
6
  .cdc-open-viz-module.type-waffle-chart {
@@ -14,4 +14,16 @@
14
14
  content: '\21BB';
15
15
  }
16
16
  }
17
+
18
+ .cove-component__content:not(.component--has-background, .component--hideBackgroundColor) {
19
+ background-color: white;
20
+ }
21
+
22
+ &.is-editor .cove-component {
23
+ padding-left: 350px;
24
+ }
25
+
26
+ &.is-editor .cove-editor__content .cove-component {
27
+ padding-left: 0px;
28
+ }
17
29
  }