@cdc/waffle-chart 4.25.11 → 4.26.1

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.
@@ -420,8 +420,8 @@ export const DataSectionTests: Story = {
420
420
  }
421
421
 
422
422
  /**
423
- * VISUAL SECTION TESTS
424
- * Tests all functionality within the Visual accordion
423
+ * CHART SETTINGS AND VISUAL SECTION TESTS
424
+ * Tests functionality within the Chart Settings and Visual accordions
425
425
  */
426
426
  export const VisualSectionTests: Story = {
427
427
  args: {
@@ -431,7 +431,8 @@ export const VisualSectionTests: Story = {
431
431
  play: async ({ canvasElement }) => {
432
432
  const canvas = within(canvasElement)
433
433
  await waitForEditor(canvas)
434
- await openAccordion(canvas, 'Visual')
434
+ // Open Chart Settings accordion first for tests 1-5
435
+ await openAccordion(canvas, 'Chart Settings')
435
436
  // Core helper functions used throughout the visual tests
436
437
  const waffleRoot = () => canvasElement.querySelector('.cove-waffle-chart') as HTMLElement
437
438
  const contentContainer = () => canvasElement.querySelector('.cove-component__content > div') as HTMLElement
@@ -569,6 +570,9 @@ export const VisualSectionTests: Story = {
569
570
  // TEST 6: Overall Font Size Change
570
571
  // Expectation: font-small|font-medium|font-large class changes on waffle root.
571
572
  // ============================================================================
573
+ // Open Visual accordion for tests 6+
574
+ await openAccordion(canvas, 'Visual')
575
+
572
576
  const overallFontClass = () => {
573
577
  const root = waffleRoot()
574
578
  if (!root) return ''
@@ -624,11 +628,8 @@ export const VisualSectionTests: Story = {
624
628
  // ============================================================================
625
629
  const contentClassSig = () => Array.from(contentContainer().classList).sort().join(' ')
626
630
 
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
631
+ // Find border checkbox by exact label text
632
+ const borderCheckbox = canvas.getByLabelText('Display Border') as HTMLInputElement
632
633
  expect(borderCheckbox).toBeTruthy()
633
634
  const borderWrapper = borderCheckbox.closest('label.checkbox') as HTMLElement
634
635
  expect(borderWrapper).toBeTruthy()
@@ -659,13 +660,8 @@ export const VisualSectionTests: Story = {
659
660
  // TEST 9: Theme Border Color Toggle
660
661
  // Expectation: Class 'component--has-borderColorTheme' toggles.
661
662
  // ============================================================================
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
- }
668
- ) as HTMLInputElement
663
+ // Find border color theme checkbox by exact label text
664
+ const borderColorThemeCheckbox = canvas.getByLabelText('Use Border Color Theme') as HTMLInputElement
669
665
  expect(borderColorThemeCheckbox).toBeTruthy()
670
666
  const borderColorThemeWrapper = borderColorThemeCheckbox.closest('label.checkbox') as HTMLElement
671
667
  expect(borderColorThemeWrapper).toBeTruthy()
@@ -682,11 +678,8 @@ export const VisualSectionTests: Story = {
682
678
  // TEST 10: Accent Style Toggle
683
679
  // Expectation: Class 'component--has-accent' toggles.
684
680
  // ============================================================================
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
681
+ // Find accent checkbox by exact label text
682
+ const accentCheckbox = canvas.getByLabelText('Use Accent Style') as HTMLInputElement
690
683
  expect(accentCheckbox).toBeTruthy()
691
684
  const accentWrapper = accentCheckbox.closest('label.checkbox') as HTMLElement
692
685
  expect(accentWrapper).toBeTruthy()
@@ -703,11 +696,8 @@ export const VisualSectionTests: Story = {
703
696
  // TEST 11: Theme Background Color Toggle
704
697
  // Expectation: Class 'component--has-background' toggles.
705
698
  // ============================================================================
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
699
+ // Find background checkbox by exact label text
700
+ const backgroundCheckbox = canvas.getByLabelText('Use Theme Background Color') as HTMLInputElement
711
701
  expect(backgroundCheckbox).toBeTruthy()
712
702
  const backgroundWrapper = backgroundCheckbox.closest('label.checkbox') as HTMLElement
713
703
  expect(backgroundWrapper).toBeTruthy()
@@ -724,11 +714,8 @@ export const VisualSectionTests: Story = {
724
714
  // TEST 12: Hide Background Color Toggle
725
715
  // Expectation: Class 'component--hideBackgroundColor' toggles.
726
716
  // ============================================================================
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
717
+ // Find hide background checkbox by exact label text
718
+ const hideBackgroundCheckbox = canvas.getByLabelText('Hide Background Color') as HTMLInputElement
732
719
  expect(hideBackgroundCheckbox).toBeTruthy()
733
720
  const hideBackgroundWrapper = hideBackgroundCheckbox.closest('label.checkbox') as HTMLElement
734
721
  expect(hideBackgroundWrapper).toBeTruthy()
@@ -189,4 +189,32 @@ export const Gauge: Story = {
189
189
  )
190
190
  }
191
191
 
192
+ export const Waffle_Chart_TP5_Style: Story = {
193
+ args: {
194
+ configUrl: '/packages/waffle-chart/examples/tp5-style.json'
195
+ },
196
+ parameters: {
197
+ docs: {
198
+ description: {
199
+ story:
200
+ 'TP5 Style - A new layout style that displays the waffle chart in a callout component with a blue background and icon. The title appears inside the callout header. This style mimics the CDC Template Package 5.0 callout component design and includes an optional white background variant.'
201
+ }
202
+ }
203
+ }
204
+ }
205
+
206
+ export const Waffle_Chart_TP5_Style_White_Background: Story = {
207
+ args: {
208
+ configUrl: '/packages/waffle-chart/examples/tp5-style-white.json'
209
+ },
210
+ parameters: {
211
+ docs: {
212
+ description: {
213
+ story:
214
+ 'TP5 Style with White Background - The white background variant of the TP5 style features a white background with a teal border instead of the default blue background. The icon remains visible in this variant.'
215
+ }
216
+ }
217
+ }
218
+ }
219
+
192
220
  export default meta
@@ -1,10 +1,9 @@
1
- import React, { useState, useEffect, memo, useContext } from 'react'
2
- import cloneConfig from '@cdc/core/helpers/cloneConfig'
1
+ import React, { useEffect, memo, useContext } from 'react'
3
2
  import _ from 'lodash'
4
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
5
3
 
6
4
  import ConfigContext from '../ConfigContext'
7
5
 
6
+ import { EditorPanel as BaseEditorPanel } from '@cdc/core/components/EditorPanel/EditorPanel'
8
7
  import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
9
8
  import Accordion from '@cdc/core/components/ui/Accordion'
10
9
  import Button from '@cdc/core/components/elements/Button'
@@ -12,8 +11,9 @@ import Icon from '@cdc/core/components/ui/Icon'
12
11
  import Tooltip from '@cdc/core/components/ui/Tooltip'
13
12
  import { TextField, Select, CheckBox } from '@cdc/core/components/EditorPanel/Inputs'
14
13
  import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
15
- import Layout from '@cdc/core/components/Layout'
16
- import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
14
+ import { useFilterManagement } from '@cdc/core/hooks/useFilterManagement'
15
+ import { useDataColumns } from '@cdc/core/hooks/useDataColumns'
16
+ import { VisualSection } from '@cdc/core/components/EditorPanel/sections/VisualSection'
17
17
 
18
18
  import '@cdc/core/styles/v2/components/editor.scss'
19
19
  import WarningImage from '../images/warning.svg'
@@ -23,27 +23,16 @@ import { DATA_OPERATORS, DATA_FUNCTIONS } from '../CdcWaffleChart'
23
23
  const EditorPanel = memo(props => {
24
24
  const { config, updateConfig, loading, data, setParentConfig, isDashboard } = useContext(ConfigContext)
25
25
  const { showConfigConfirm } = props
26
- const [displayPanel, setDisplayPanel] = useState(true)
27
26
  const inputSelectStyle = condition => (condition ? { backgroundColor: '#ffd2d2', color: '#d8000c' } : {})
28
27
 
29
28
  const updateField = updateFieldFactory(config, updateConfig, true)
30
29
 
31
- useEffect(() => {
32
- // Pass up to Editor if needed
33
- if (setParentConfig) {
34
- const newConfig = convertStateToConfig()
35
- setParentConfig(newConfig)
36
- }
37
- // eslint-disable-next-line react-hooks/exhaustive-deps
38
- }, [config])
39
-
40
- useEffect(() => {
41
- if (!showConfigConfirm) {
42
- let newConfig = { ...config }
43
- delete newConfig.newViz
44
- updateConfig(newConfig)
45
- }
46
- }, [])
30
+ // Filters
31
+ const { addNewFilter, removeFilter, updateFilterProp, getFilterColumnValues } = useFilterManagement(
32
+ config,
33
+ updateConfig,
34
+ data
35
+ )
47
36
 
48
37
  useEffect(() => {
49
38
  //Verify comparate data type
@@ -61,70 +50,15 @@ const EditorPanel = memo(props => {
61
50
  }
62
51
  }, [config.dataConditionalOperator, config.dataConditionalComparate])
63
52
 
64
- const onBackClick = () => {
65
- setDisplayPanel(!displayPanel)
66
- updateConfig({
67
- ...config,
68
- showEditorPanel: !displayPanel
69
- })
70
-
71
- // if (isDashboard) {
72
- // updateConfig({ ...config, editing: false })
73
- // } else {
74
- // setDisplayPanel(!displayPanel)
75
- // }
76
- }
77
-
78
- const convertStateToConfig = () => {
79
- let strippedState = cloneConfig(config)
80
- delete strippedState.newViz
81
- delete strippedState.runtime
82
-
83
- return strippedState
84
- }
85
-
86
- const addNewFilter = () => {
87
- let filters = config.filters ? [...config.filters] : []
88
- filters.push({ values: [] })
89
- updateConfig({ ...config, filters })
90
- }
91
-
92
- const removeFilter = index => {
93
- let filters = [...config.filters]
94
- filters.splice(index, 1)
95
- updateConfig({ ...config, filters })
96
- }
97
-
98
- const updateFilterProp = (name, index, value) => {
99
- let filters = [...config.filters]
100
- filters[index][name] = value
101
- updateConfig({ ...config, filters })
102
- }
103
-
104
- const getColumns = (filter = true) => {
105
- let columns = {}
106
-
107
- data.map(row => Object.keys(row).forEach(columnName => (columns[columnName] = true)))
108
-
109
- return Object.keys(columns)
110
- }
111
-
112
- const getFilterColumnValues = index => {
113
- let filterDataOptions = []
114
- const filterColumnName = config.filters[index].columnName
115
- if (data && filterColumnName) {
116
- data.forEach(function (row) {
117
- if (undefined !== row[filterColumnName] && -1 === filterDataOptions.indexOf(row[filterColumnName])) {
118
- filterDataOptions.push(row[filterColumnName])
119
- }
120
- })
121
- filterDataOptions.sort()
122
- }
123
- return filterDataOptions
124
- }
53
+ // Extract column names from data with memoization (replaces getColumns)
54
+ const columns = useDataColumns(data)
125
55
  //visualizationType
126
56
 
127
- const approvedWaffleChartOptions = ['Waffle', 'Gauge']
57
+ const approvedWaffleChartOptions = [
58
+ { value: 'Waffle', label: 'Waffle' },
59
+ { value: 'TP5 Waffle', label: 'TP5 Style Waffle' },
60
+ { value: 'Gauge', label: 'Gauge' }
61
+ ]
128
62
 
129
63
  const editorContent = (
130
64
  <Accordion>
@@ -210,7 +144,7 @@ const EditorPanel = memo(props => {
210
144
  label='Data Column'
211
145
  updateField={updateField}
212
146
  initial='Select'
213
- options={getColumns()}
147
+ options={columns}
214
148
  />
215
149
  </div>
216
150
 
@@ -237,7 +171,7 @@ const EditorPanel = memo(props => {
237
171
  fieldName='dataConditionalColumn'
238
172
  updateField={updateField}
239
173
  initial='Select'
240
- options={getColumns()}
174
+ options={columns}
241
175
  />
242
176
  </div>
243
177
  <div className='cove-accordion__panel-col'>
@@ -297,7 +231,7 @@ const EditorPanel = memo(props => {
297
231
  label='Data Column'
298
232
  updateField={updateField}
299
233
  initial='Select'
300
- options={getColumns()}
234
+ options={columns}
301
235
  />
302
236
  <Select
303
237
  value={config.dataDenomFunction || ''}
@@ -387,7 +321,7 @@ const EditorPanel = memo(props => {
387
321
  <Select
388
322
  label='Column'
389
323
  value={filter.columnName || ''}
390
- options={getColumns()}
324
+ options={columns}
391
325
  initial='- Select Option -'
392
326
  onChange={e => {
393
327
  updateFilterProp('columnName', index, e.target.value)
@@ -410,7 +344,7 @@ const EditorPanel = memo(props => {
410
344
  Add Filter
411
345
  </Button>
412
346
  </Accordion.Section>
413
- <Accordion.Section title='Visual' className='panel-visual'>
347
+ <Accordion.Section title='Chart Settings'>
414
348
  {config.visualizationType !== 'Gauge' && (
415
349
  <Select
416
350
  value={config.shape}
@@ -420,133 +354,110 @@ const EditorPanel = memo(props => {
420
354
  options={['circle', 'square', 'person']}
421
355
  />
422
356
  )}
423
- {config.visualizationType !== 'Gauge' && (
424
- <div
425
- className='cove-accordion__panel-row cove-accordion__small-inputs'
426
- style={{ marginTop: '1rem', marginBottom: '1rem' }}
427
- >
428
- <div className='cove-accordion__panel-col'>
429
- <TextField
430
- type='number'
431
- value={config.nodeWidth}
432
- fieldName='nodeWidth'
433
- label='Width'
434
- updateField={updateField}
435
- />
357
+ {config.visualizationType !== 'Gauge' && config.visualizationType !== 'TP5 Waffle' && (
358
+ <>
359
+ <div
360
+ className='cove-accordion__panel-row cove-accordion__small-inputs'
361
+ style={{ marginTop: '1rem', marginBottom: '1rem' }}
362
+ >
363
+ <div className='cove-accordion__panel-col'>
364
+ <TextField
365
+ type='number'
366
+ value={config.nodeWidth}
367
+ fieldName='nodeWidth'
368
+ label='Width'
369
+ updateField={updateField}
370
+ />
371
+ </div>
372
+ <div className='cove-accordion__panel-col'>
373
+ <TextField
374
+ type='number'
375
+ value={config.nodeSpacer}
376
+ fieldName='nodeSpacer'
377
+ label='Spacer'
378
+ updateField={updateField}
379
+ />
380
+ </div>
436
381
  </div>
437
- <div className='cove-accordion__panel-col'>
438
- <TextField
439
- type='number'
440
- value={config.nodeSpacer}
441
- fieldName='nodeSpacer'
442
- label='Spacer'
382
+
383
+ <div className='cove-input-group'>
384
+ <Select
385
+ value={config.orientation}
386
+ fieldName='orientation'
387
+ label='Layout'
443
388
  updateField={updateField}
389
+ options={['horizontal', 'vertical']}
444
390
  />
445
391
  </div>
446
- </div>
447
- )}
448
392
 
449
- <div className='cove-input-group'>
450
- {config.visualizationType !== 'Gauge' && (
451
- <Select
452
- value={config.orientation}
453
- fieldName='orientation'
454
- label='Layout'
455
- updateField={updateField}
456
- options={['horizontal', 'vertical']}
457
- />
458
- )}
459
- </div>
460
-
461
- <div className='cove-input-group'>
462
- <label>
463
- <span className='edit-label column-heading cove-input__label'>Data Point Font Size</span>
464
- </label>
465
- <div className='cove-accordion__panel-row cove-accordion__small-inputs align-center'>
466
- <div className='cove-accordion__panel-col'>
467
- <TextField type='number' value={config.fontSize} fieldName='fontSize' updateField={updateField} />
468
- </div>
469
- <div className='cove-accordion__panel-col' style={{ display: 'flex', alignItems: 'center' }}>
470
- <label className='accordion__panel-label--muted'> default (50px)</label>
393
+ <div className='cove-input-group'>
394
+ <label>
395
+ <span className='edit-label column-heading cove-input__label'>Data Point Font Size</span>
396
+ </label>
397
+ <div className='cove-accordion__panel-row cove-accordion__small-inputs align-center'>
398
+ <div className='cove-accordion__panel-col'>
399
+ <TextField type='number' value={config.fontSize} fieldName='fontSize' updateField={updateField} />
400
+ </div>
401
+ <div className='cove-accordion__panel-col' style={{ display: 'flex', alignItems: 'center' }}>
402
+ <label className='accordion__panel-label--muted'> default (50px)</label>
403
+ </div>
404
+ </div>
471
405
  </div>
472
- </div>
473
- </div>
474
-
475
- <Select
476
- value={config.overallFontSize}
477
- fieldName='overallFontSize'
478
- label='Overall Font Size'
479
- updateField={updateField}
480
- options={['small', 'medium', 'large']}
481
- />
482
-
483
- <HeaderThemeSelector
484
- selectedTheme={config.theme}
485
- onThemeSelect={theme => updateConfig({ ...config, theme })}
486
- label='Theme'
487
- />
406
+ </>
407
+ )}
408
+ </Accordion.Section>
488
409
 
489
- <div className='cove-accordion__panel-section reverse-labels'>
490
- <CheckBox
491
- value={config.visual.border}
492
- section='visual'
493
- fieldName='border'
494
- label='Display Border'
495
- updateField={updateField}
496
- />
497
- <CheckBox
498
- value={config.visual.borderColorTheme}
499
- section='visual'
500
- fieldName='borderColorTheme'
501
- label='Use theme border color'
502
- updateField={updateField}
503
- />
504
- <CheckBox
505
- value={config.visual.accent}
506
- section='visual'
507
- fieldName='accent'
508
- label='Use Accent Style'
509
- updateField={updateField}
510
- />
410
+ {/* Visual section for TP5 style */}
411
+ {config.visualizationType === 'TP5 Waffle' && (
412
+ <Accordion.Section title='Visual'>
511
413
  <CheckBox
512
- value={config.visual.background}
414
+ value={config.visual?.whiteBackground}
513
415
  section='visual'
514
- fieldName='background'
515
- label='Use Theme Background Color'
416
+ fieldName='whiteBackground'
417
+ label='Use White Background Style'
516
418
  updateField={updateField}
517
419
  />
518
- <CheckBox
519
- value={config.visual.hideBackgroundColor}
520
- section='visual'
521
- fieldName='hideBackgroundColor'
522
- label='Hide Background Color'
420
+ </Accordion.Section>
421
+ )}
422
+
423
+ {/* Visual section for other styles */}
424
+ {config.visualizationType !== 'TP5 Waffle' && (
425
+ <Accordion.Section title='Visual'>
426
+ <VisualSection
427
+ config={config}
523
428
  updateField={updateField}
429
+ updateConfig={updateConfig}
430
+ beforeCheckboxes={
431
+ <Select
432
+ value={config.overallFontSize}
433
+ fieldName='overallFontSize'
434
+ label='Overall Font Size'
435
+ updateField={updateField}
436
+ options={['small', 'medium', 'large']}
437
+ />
438
+ }
524
439
  />
525
- </div>
526
- </Accordion.Section>
440
+ </Accordion.Section>
441
+ )}
527
442
  </Accordion>
528
443
  )
529
444
 
530
- if (loading) return null
531
-
532
445
  return (
533
- <ErrorBoundary component='EditorPanel'>
534
- <>
535
- <Layout.Sidebar
536
- displayPanel={displayPanel}
537
- onBackClick={onBackClick}
538
- isDashboard={isDashboard}
539
- title='Configure Waffle Chart'
540
- showEditorPanel={displayPanel}
541
- >
542
- <>
543
- {editorContent}
544
- <AdvancedEditor loadConfig={updateConfig} config={config} convertStateToConfig={convertStateToConfig} />
545
- </>
546
- </Layout.Sidebar>
547
- {props.children}
548
- </>
549
- </ErrorBoundary>
446
+ <BaseEditorPanel
447
+ config={config}
448
+ updateConfig={updateConfig}
449
+ loading={loading}
450
+ setParentConfig={setParentConfig}
451
+ isDashboard={isDashboard}
452
+ title='Configure Waffle Chart'
453
+ >
454
+ {({ convertStateToConfig }) => (
455
+ <>
456
+ {editorContent}
457
+ <AdvancedEditor loadConfig={updateConfig} config={config} convertStateToConfig={convertStateToConfig} />
458
+ </>
459
+ )}
460
+ </BaseEditorPanel>
550
461
  )
551
462
  })
552
463
 
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
3
+ <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="481.000000pt" height="563.000000pt" viewBox="0 0 481.000000 563.000000" preserveAspectRatio="xMidYMid meet">
4
+ <g transform="translate(0.000000,563.000000) scale(0.100000,-0.100000)" fill="#2c7a99" stroke="none">
5
+ <path d="M890 5514 c-161 -43 -308 -201 -354 -381 -14 -55 -16 -314 -16 -2527 0 -2015 2 -2466 13 -2466 7 0 51 14 97 30 47 17 92 33 100 35 8 2 16 4 18 5 1 2 7 4 12 5 6 1 11 3 13 4 1 2 13 4 26 7 14 2 30 9 38 15 7 6 13 8 13 4 0 -4 7 -2 15 5 8 7 15 10 15 6 0 -3 17 1 38 10 49 21 856 293 905 305 21 5 45 13 55 19 9 5 40 16 67 24 28 8 162 52 299 99 l249 85 151 -53 c83 -29 253 -90 379 -134 264 -94 556 -198 974 -346 164 -58 308 -110 321 -115 13 -6 27 -10 33 -10 11 0 8 4951 -4 4994 -22 80 -84 183 -152 252 -75 76 -141 114 -233 133 -38 8 -477 11 -1535 10 -1268 0 -1490 -3 -1537 -15z m2687 -1570 c49 -31 82 -134 64 -201 -10 -37 -41 -64 -422 -369 -227 -181 -430 -341 -452 -356 -43 -30 -84 -35 -136 -17 -17 6 -156 107 -309 224 l-277 213 -40 -31 c-50 -39 -318 -259 -325 -267 -3 -3 -27 -24 -55 -45 -27 -22 -55 -44 -61 -50 -86 -77 -253 -202 -277 -207 -20 -4 -53 -1 -84 8 -69 19 -105 64 -111 140 -6 70 8 100 69 149 105 84 134 107 168 133 19 15 92 74 164 132 71 58 144 116 162 130 86 68 114 90 187 150 124 102 156 120 206 120 23 0 57 -7 75 -16 18 -9 145 -103 282 -209 283 -217 293 -224 303 -210 4 6 42 39 86 74 43 35 88 71 100 81 31 27 153 127 231 190 37 30 111 91 164 135 142 119 217 145 288 99z m-1431 -983 c60 -44 59 -29 62 -601 3 -596 4 -589 -70 -638 -76 -49 -171 -29 -228 50 l-30 41 0 526 c0 591 -3 569 75 623 35 25 48 28 100 25 44 -2 69 -9 91 -26z m1252 15 c37 -19 67 -55 81 -95 8 -25 10 -183 9 -555 -3 -579 -1 -555 -71 -603 -67 -45 -144 -35 -211 27 l-41 39 -3 543 -2 544 23 35 c46 68 149 99 215 65z m-610 -343 c71 -57 71 -57 71 -448 0 -322 -1 -353 -19 -392 -27 -60 -83 -95 -155 -95 -63 -1 -95 16 -132 72 -23 33 -23 36 -23 407 0 406 -1 401 57 455 34 32 54 38 116 34 35 -2 57 -11 85 -33z m-1313 -142 c54 -24 92 -71 100 -124 4 -23 5 -159 3 -302 -3 -293 -3 -293 -82 -343 -66 -41 -160 -30 -207 24 -34 40 -39 84 -39 361 0 303 3 322 61 366 53 39 105 45 164 18z"/>
6
+ </g>
7
+ </svg>
@@ -1,6 +1,5 @@
1
1
  // Remove custom theme mixin - use core styles instead
2
2
 
3
-
4
3
  .type-dashboard .type-waffle-chart .cove-component__content {
5
4
  padding-top: 0;
6
5
  }
@@ -19,7 +18,7 @@
19
18
  justify-items: center;
20
19
  align-items: flex-start;
21
20
 
22
- &>svg {
21
+ & > svg {
23
22
  margin: 0.7em 0;
24
23
  }
25
24
  }
@@ -97,7 +96,6 @@
97
96
  }
98
97
 
99
98
  @at-root {
100
-
101
99
  .cove-waffle-chart.font-small,
102
100
  .cove-gauge-chart.font-small #{&} {
103
101
  .cove-waffle-chart__data--primary {
@@ -130,4 +128,88 @@
130
128
  font-size: 20px;
131
129
  }
132
130
  }
133
- }
131
+ }
132
+
133
+ // TP5 Style for Waffle Chart
134
+ .type-waffle-chart {
135
+ &.waffle__style--tp5 {
136
+ .cove-component__content {
137
+ background: none !important;
138
+ }
139
+
140
+ .cdc-callout {
141
+ box-shadow: 0 2px 4px rgb(159 159 159 / 10%);
142
+ margin: 0 !important;
143
+ padding: 1.5rem;
144
+ background-color: var(--colors-cyan-10, #eff9fa);
145
+ border: 1px solid var(--colors-cyan-15, #dff2f6);
146
+ position: relative;
147
+ border-radius: 0.25rem;
148
+ flex-wrap: wrap;
149
+ gap: 0.5rem;
150
+ }
151
+
152
+ .cdc-callout__icon {
153
+ position: absolute;
154
+ font-family: var(--icons-cdc);
155
+ top: -0.65rem;
156
+ right: 1rem;
157
+ font-size: 2rem;
158
+ color: var(--colors-cyan-60v);
159
+ }
160
+
161
+ .cdc-callout__flag {
162
+ position: absolute;
163
+ top: -0.25rem;
164
+ right: 1.08rem;
165
+ width: 1.85rem;
166
+ height: auto;
167
+ }
168
+
169
+ .cove-waffle-chart {
170
+ padding: 0;
171
+ row-gap: 1rem;
172
+ }
173
+
174
+ .cove-waffle-chart__chart {
175
+ margin-bottom: 0;
176
+ }
177
+
178
+ .cove-waffle-chart__data {
179
+ margin-bottom: 0;
180
+ align-content: flex-start;
181
+ }
182
+
183
+ .cdc-callout__heading {
184
+ font-family: var(--fonts-nunito) !important;
185
+ width: 100%;
186
+ font-size: 1.1rem;
187
+ }
188
+
189
+ .cove-waffle-chart__data--text {
190
+ margin-top: 0.5rem;
191
+ font-size: 1rem;
192
+ }
193
+ .cove-waffle-chart__subtext {
194
+ font-size: 1rem;
195
+ }
196
+ .cove-waffle-chart__data--primary {
197
+ font-size: 2rem;
198
+ color: var(--colors-cyan-60v);
199
+ font-weight: 400;
200
+ }
201
+
202
+ // White background variant (when "Use White Background Style" is checked)
203
+ &.white-background-style {
204
+ .cove-component__content {
205
+ background: white !important;
206
+ }
207
+
208
+ .cdc-callout {
209
+ background: transparent !important;
210
+ border: 1px solid #009ec1 !important;
211
+ box-shadow: 0 2px 4px rgb(159 159 159 / 10%);
212
+ }
213
+ }
214
+ }
215
+ }
@@ -7,5 +7,5 @@ describe('Waffle Chart', () => {
7
7
  const pkgDir = path.join(__dirname, '..')
8
8
  const result = testStandaloneBuild(pkgDir)
9
9
  expect(result).toBe(true)
10
- })
10
+ }, 300000)
11
11
  })