@cdc/waffle-chart 4.25.10 → 4.25.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/waffle-chart",
3
- "version": "4.25.10",
3
+ "version": "4.25.11",
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",
@@ -27,7 +27,7 @@
27
27
  "license": "Apache-2.0",
28
28
  "homepage": "https://github.com/CDCgov/cdc-open-viz#readme",
29
29
  "dependencies": {
30
- "@cdc/core": "^4.25.10",
30
+ "@cdc/core": "^4.25.11",
31
31
  "@visx/shape": "^3.12.0",
32
32
  "@visx/text": "^3.12.0",
33
33
  "chroma": "0.0.1",
@@ -40,11 +40,10 @@
40
40
  "react-dom": "^18.2.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@rollup/plugin-dsv": "^3.0.2",
44
43
  "@vitejs/plugin-react": "^4.3.4",
45
44
  "vite": "^4.4.11",
46
45
  "vite-plugin-css-injected-by-js": "^2.4.0",
47
46
  "vite-plugin-svgr": "^2.4.0"
48
47
  },
49
- "gitHead": "c2db758e74ab9b9ca1667a6f9cb41dd0dccf985d"
48
+ "gitHead": "5f09a137c22f454111ab5f4cd7fdf1d2d58e31bd"
50
49
  }
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useEffect, useReducer, useState } from 'react'
1
+ import React, { useCallback, useEffect, useMemo, useReducer, useState } from 'react'
2
2
 
3
3
  // visx
4
4
  import { Circle, Bar } from '@visx/shape'
@@ -13,6 +13,7 @@ import ResizeObserver from 'resize-observer-polyfill'
13
13
  import { Config } from './types/Config'
14
14
  import getViewport from '@cdc/core/helpers/getViewport'
15
15
  import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData'
16
+ import { DATA_OPERATORS } from '@cdc/core/helpers/constants'
16
17
 
17
18
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
18
19
  import Loading from '@cdc/core/components/Loading'
@@ -67,7 +68,7 @@ const WaffleChart = ({ config, isEditor, link = '', showConfigConfirm, updateCon
67
68
  const gaugeColor = config.visual.colors[config.theme]
68
69
  let dataFontSize = config.fontSize ? { fontSize: config.fontSize + 'px' } : null
69
70
 
70
- const calculateData = useCallback(() => {
71
+ const [dataPercentage, waffleDenominator, waffleNumerator] = useMemo(() => {
71
72
  //If either the column or function aren't set, do not calculate
72
73
  if (!dataColumn || !dataFunction) {
73
74
  return ''
@@ -239,22 +240,20 @@ const WaffleChart = ({ config, isEditor, link = '', showConfigConfirm, updateCon
239
240
  applyPrecision(waffleNumerator)
240
241
  ]
241
242
  }, [
242
- dataColumn,
243
- dataFunction,
244
243
  config.data,
245
244
  filters,
245
+ dataColumn,
246
+ dataFunction,
246
247
  dataConditionalColumn,
247
248
  dataConditionalOperator,
248
249
  dataConditionalComparate,
249
250
  customDenom,
251
+ dataDenom,
250
252
  dataDenomColumn,
251
253
  dataDenomFunction,
252
- roundToPlace,
253
- dataDenom
254
+ roundToPlace
254
255
  ])
255
256
 
256
- const [dataPercentage, waffleDenominator, waffleNumerator] = calculateData()
257
-
258
257
  const buildWaffle = useCallback(() => {
259
258
  let waffleData = []
260
259
  let nodeWidthNum = parseInt(nodeWidth, 10)
@@ -579,18 +578,5 @@ export const DATA_FUNCTIONS = [
579
578
  DATA_FUNCTION_SUM
580
579
  ]
581
580
 
582
- export const DATA_OPERATOR_LESS = '<'
583
- export const DATA_OPERATOR_GREATER = '>'
584
- export const DATA_OPERATOR_LESSEQUAL = '<='
585
- export const DATA_OPERATOR_GREATEREQUAL = '>='
586
- export const DATA_OPERATOR_EQUAL = '='
587
- export const DATA_OPERATOR_NOTEQUAL = '≠'
588
-
589
- export const DATA_OPERATORS = [
590
- DATA_OPERATOR_LESS,
591
- DATA_OPERATOR_GREATER,
592
- DATA_OPERATOR_LESSEQUAL,
593
- DATA_OPERATOR_GREATEREQUAL,
594
- DATA_OPERATOR_EQUAL,
595
- DATA_OPERATOR_NOTEQUAL
596
- ]
581
+ // Re-export DATA_OPERATORS for backward compatibility
582
+ export { DATA_OPERATORS }
@@ -100,8 +100,12 @@ export const GeneralSectionTests: Story = {
100
100
  // TEST 3: Show Title Toggle
101
101
  // Expectation: Header region appears / disappears (DOM visibility change).
102
102
  // ============================================================================
103
- const showTitleCheckbox = canvasElement.querySelector('input[name*="showTitle"]') as HTMLInputElement
104
- const checkboxWrapper = showTitleCheckbox?.closest('.cove-input__checkbox--small')
103
+ // Find show title checkbox by label text
104
+ const showTitleCheckbox = Array.from(canvasElement.querySelectorAll('input[type="checkbox"]')).find(input => {
105
+ const label = input.closest('label')
106
+ return label?.textContent?.includes('show title')
107
+ }) as HTMLInputElement
108
+ const checkboxWrapper = showTitleCheckbox?.closest('label.checkbox')
105
109
  expect(showTitleCheckbox).toBeTruthy()
106
110
  expect(checkboxWrapper).toBeTruthy()
107
111
 
@@ -110,7 +114,7 @@ export const GeneralSectionTests: Story = {
110
114
  'Title Toggle',
111
115
  () => showTitleCheckbox.checked,
112
116
  async () => {
113
- await userEvent.click(checkboxWrapper as HTMLElement)
117
+ await userEvent.click(showTitleCheckbox)
114
118
  },
115
119
  (before, after) => after === !wasChecked
116
120
  )
@@ -128,7 +132,7 @@ export const GeneralSectionTests: Story = {
128
132
  'Title Toggle Reset',
129
133
  () => showTitleCheckbox.checked,
130
134
  async () => {
131
- await userEvent.click(checkboxWrapper as HTMLElement)
135
+ await userEvent.click(showTitleCheckbox)
132
136
  },
133
137
  (before, after) => after === wasChecked
134
138
  )
@@ -253,7 +257,15 @@ export const DataSectionTests: Story = {
253
257
  'Clear Conditional Value',
254
258
  getValueText,
255
259
  async () => {
260
+ // Clear the conditional column to fully reset the filter
261
+ const conditionalColumnSelect = canvasElement.querySelector(
262
+ 'select[name="dataConditionalColumn"]'
263
+ ) as HTMLSelectElement
264
+ await userEvent.selectOptions(conditionalColumnSelect, '')
256
265
  await userEvent.clear(conditionalValueInput)
266
+ conditionalValueInput.blur() // Trigger change event
267
+ // Wait for debounced input processing (TextField uses 500ms debounce)
268
+ await new Promise(resolve => setTimeout(resolve, 600))
257
269
  },
258
270
  (before, after) => after !== before
259
271
  )
@@ -312,7 +324,7 @@ export const DataSectionTests: Story = {
312
324
  'Custom Denominator Toggle',
313
325
  getValueText,
314
326
  async () => {
315
- await userEvent.click(customDenomWrapper)
327
+ await userEvent.click(customDenomCheckbox)
316
328
  },
317
329
  (before, after) => after !== before
318
330
  )
@@ -404,32 +416,6 @@ export const DataSectionTests: Story = {
404
416
  },
405
417
  (before, after) => after !== before && after.endsWith('deaths')
406
418
  )
407
-
408
- // ============================================================================
409
- // TEST 16: Add Filter (state = Alaska)
410
- // Expectation: Primary value text changes after filter applied.
411
- // ============================================================================
412
- const addFilterButton = Array.from(canvasElement.querySelectorAll('button')).find(
413
- b => (b as HTMLButtonElement).textContent?.trim() === 'Add Filter'
414
- ) as HTMLButtonElement
415
- await performAndAssert(
416
- 'Add Filter',
417
- getValueText,
418
- async () => {
419
- await userEvent.click(addFilterButton)
420
-
421
- await waitForPresence('.filters-list .edit-block:last-of-type', canvasElement)
422
-
423
- const newFilter = canvasElement.querySelector('.filters-list .edit-block:last-of-type') as HTMLElement
424
- const [colSelect, valSelect] = Array.from(newFilter.querySelectorAll('select')) as HTMLSelectElement[]
425
- await userEvent.selectOptions(colSelect, 'state')
426
-
427
- await waitForOptionsToPopulate(valSelect)
428
-
429
- await userEvent.selectOptions(valSelect, 'Alaska')
430
- },
431
- (before, after) => after !== before
432
- )
433
419
  }
434
420
  }
435
421
 
@@ -618,7 +604,7 @@ export const VisualSectionTests: Story = {
618
604
  return node?.getAttribute('fill') || ''
619
605
  }
620
606
 
621
- const themeButtons = Array.from(canvasElement.querySelectorAll('.color-palette li')) as HTMLElement[]
607
+ const themeButtons = Array.from(canvasElement.querySelectorAll('.color-palette button')) as HTMLElement[]
622
608
  expect(themeButtons.length).toBeGreaterThan(1)
623
609
  await performAndAssert(
624
610
  'Theme Change',
@@ -638,9 +624,13 @@ export const VisualSectionTests: Story = {
638
624
  // ============================================================================
639
625
  const contentClassSig = () => Array.from(contentContainer().classList).sort().join(' ')
640
626
 
641
- const borderCheckbox = canvasElement.querySelector('input[name="visual-null-border"]') as HTMLInputElement
627
+ // Find border checkbox by label text instead of name attribute
628
+ const borderCheckbox = Array.from(canvasElement.querySelectorAll('input[type="checkbox"]')).find(input => {
629
+ const label = input.closest('label')
630
+ return label?.textContent?.includes('Display Border')
631
+ }) as HTMLInputElement
642
632
  expect(borderCheckbox).toBeTruthy()
643
- const borderWrapper = borderCheckbox.closest('.cove-input__checkbox--small') as HTMLElement
633
+ const borderWrapper = borderCheckbox.closest('label.checkbox') as HTMLElement
644
634
  expect(borderWrapper).toBeTruthy()
645
635
  const borderStyleSig = () => {
646
636
  const el = contentContainer()
@@ -656,7 +646,7 @@ export const VisualSectionTests: Story = {
656
646
  'Border Toggle',
657
647
  borderStyleSig,
658
648
  async () => {
659
- await userEvent.click(borderWrapper)
649
+ await userEvent.click(borderCheckbox)
660
650
  },
661
651
  (before, after) =>
662
652
  before.classes !== after.classes ||
@@ -669,17 +659,21 @@ export const VisualSectionTests: Story = {
669
659
  // TEST 9: Theme Border Color Toggle
670
660
  // Expectation: Class 'component--has-borderColorTheme' toggles.
671
661
  // ============================================================================
672
- const borderColorThemeCheckbox = canvasElement.querySelector(
673
- 'input[name="visual-null-borderColorTheme"]'
662
+ // Find border color theme checkbox by label text
663
+ const borderColorThemeCheckbox = Array.from(canvasElement.querySelectorAll('input[type="checkbox"]')).find(
664
+ input => {
665
+ const label = input.closest('label')
666
+ return label?.textContent?.includes('Use theme border color')
667
+ }
674
668
  ) as HTMLInputElement
675
669
  expect(borderColorThemeCheckbox).toBeTruthy()
676
- const borderColorThemeWrapper = borderColorThemeCheckbox.closest('.cove-input__checkbox--small') as HTMLElement
670
+ const borderColorThemeWrapper = borderColorThemeCheckbox.closest('label.checkbox') as HTMLElement
677
671
  expect(borderColorThemeWrapper).toBeTruthy()
678
672
  await performAndAssert(
679
673
  'Border Color Theme Toggle',
680
674
  contentClassSig,
681
675
  async () => {
682
- await userEvent.click(borderColorThemeWrapper)
676
+ await userEvent.click(borderColorThemeCheckbox)
683
677
  },
684
678
  (before, after) => before !== after && (after.includes('borderColorTheme') || before.includes('borderColorTheme'))
685
679
  )
@@ -688,15 +682,19 @@ export const VisualSectionTests: Story = {
688
682
  // TEST 10: Accent Style Toggle
689
683
  // Expectation: Class 'component--has-accent' toggles.
690
684
  // ============================================================================
691
- const accentCheckbox = canvasElement.querySelector('input[name="visual-null-accent"]') as HTMLInputElement
685
+ // Find accent checkbox by label text
686
+ const accentCheckbox = Array.from(canvasElement.querySelectorAll('input[type="checkbox"]')).find(input => {
687
+ const label = input.closest('label')
688
+ return label?.textContent?.includes('Use Accent Style')
689
+ }) as HTMLInputElement
692
690
  expect(accentCheckbox).toBeTruthy()
693
- const accentWrapper = accentCheckbox.closest('.cove-input__checkbox--small') as HTMLElement
691
+ const accentWrapper = accentCheckbox.closest('label.checkbox') as HTMLElement
694
692
  expect(accentWrapper).toBeTruthy()
695
693
  await performAndAssert(
696
694
  'Accent Toggle',
697
695
  contentClassSig,
698
696
  async () => {
699
- await userEvent.click(accentWrapper)
697
+ await userEvent.click(accentCheckbox)
700
698
  },
701
699
  (before, after) => before !== after
702
700
  )
@@ -705,15 +703,19 @@ export const VisualSectionTests: Story = {
705
703
  // TEST 11: Theme Background Color Toggle
706
704
  // Expectation: Class 'component--has-background' toggles.
707
705
  // ============================================================================
708
- const backgroundCheckbox = canvasElement.querySelector('input[name="visual-null-background"]') as HTMLInputElement
706
+ // Find background checkbox by label text
707
+ const backgroundCheckbox = Array.from(canvasElement.querySelectorAll('input[type="checkbox"]')).find(input => {
708
+ const label = input.closest('label')
709
+ return label?.textContent?.includes('Use Theme Background Color')
710
+ }) as HTMLInputElement
709
711
  expect(backgroundCheckbox).toBeTruthy()
710
- const backgroundWrapper = backgroundCheckbox.closest('.cove-input__checkbox--small') as HTMLElement
712
+ const backgroundWrapper = backgroundCheckbox.closest('label.checkbox') as HTMLElement
711
713
  expect(backgroundWrapper).toBeTruthy()
712
714
  await performAndAssert(
713
715
  'Background Toggle',
714
716
  contentClassSig,
715
717
  async () => {
716
- await userEvent.click(backgroundWrapper)
718
+ await userEvent.click(backgroundCheckbox)
717
719
  },
718
720
  (before, after) => before !== after
719
721
  )
@@ -722,17 +724,19 @@ export const VisualSectionTests: Story = {
722
724
  // TEST 12: Hide Background Color Toggle
723
725
  // Expectation: Class 'component--hideBackgroundColor' toggles.
724
726
  // ============================================================================
725
- const hideBackgroundCheckbox = canvasElement.querySelector(
726
- 'input[name="visual-null-hideBackgroundColor"]'
727
- ) as HTMLInputElement
727
+ // Find hide background checkbox by label text
728
+ const hideBackgroundCheckbox = Array.from(canvasElement.querySelectorAll('input[type="checkbox"]')).find(input => {
729
+ const label = input.closest('label')
730
+ return label?.textContent?.includes('Hide Background Color')
731
+ }) as HTMLInputElement
728
732
  expect(hideBackgroundCheckbox).toBeTruthy()
729
- const hideBackgroundWrapper = hideBackgroundCheckbox.closest('.cove-input__checkbox--small') as HTMLElement
733
+ const hideBackgroundWrapper = hideBackgroundCheckbox.closest('label.checkbox') as HTMLElement
730
734
  expect(hideBackgroundWrapper).toBeTruthy()
731
735
  await performAndAssert(
732
736
  'Hide Background Toggle',
733
737
  contentClassSig,
734
738
  async () => {
735
- await userEvent.click(hideBackgroundWrapper)
739
+ await userEvent.click(hideBackgroundCheckbox)
736
740
  },
737
741
  (before, after) => before !== after
738
742
  )
@@ -75,12 +75,29 @@ export const Person: Story = {
75
75
  showDenominator: false,
76
76
  showPercent: true,
77
77
  valueDescription: 'testing',
78
+ gauge: {
79
+ height: 35,
80
+ width: 400
81
+ },
78
82
  visual: {
79
83
  border: true,
80
84
  accent: true,
81
85
  background: true,
82
86
  hideBackgroundColor: true,
83
- borderColorTheme: true
87
+ borderColorTheme: true,
88
+ colors: {
89
+ 'theme-blue': '#005eaa',
90
+ 'theme-purple': '#712177',
91
+ 'theme-brown': '#705043',
92
+ 'theme-teal': '#00695c',
93
+ 'theme-pink': '#af4448',
94
+ 'theme-orange': '#bb4d00',
95
+ 'theme-slate': '#29434e',
96
+ 'theme-indigo': '#26418f',
97
+ 'theme-cyan': '#006778',
98
+ 'theme-green': '#4b830d',
99
+ 'theme-amber': '#fbab18'
100
+ }
84
101
  }
85
102
  }
86
103
  },