@cdc/waffle-chart 4.26.1 → 4.26.2

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.
@@ -729,3 +729,240 @@ export const VisualSectionTests: Story = {
729
729
  )
730
730
  }
731
731
  }
732
+
733
+ /**
734
+ * TP5 GAUGE - GENERAL SECTION TESTS
735
+ * Tests all functionality within the General accordion for TP5 Gauge configs.
736
+ */
737
+ export const TP5GaugeGeneralSectionTests: Story = {
738
+ args: {
739
+ configUrl: '/packages/waffle-chart/examples/tp5-gauge.json',
740
+ isEditor: true
741
+ },
742
+ play: async ({ canvasElement }) => {
743
+ const canvas = within(canvasElement)
744
+ await waitForEditor(canvas)
745
+ await openAccordion(canvas, 'General')
746
+ await waitForPresence('.cdc-callout', canvasElement)
747
+
748
+ // ============================================================================
749
+ // TEST 1: Chart Type Change (TP5 Gauge <-> TP5 Waffle)
750
+ // Expectation: Gauge container swaps with waffle container.
751
+ // ============================================================================
752
+ const chartTypeSelect = canvas.getByLabelText(/chart type/i) as HTMLSelectElement
753
+ expect(chartTypeSelect).toBeTruthy()
754
+
755
+ const getChartTypeState = () => ({
756
+ hasGauge: !!canvasElement.querySelector('.cove-gauge-chart'),
757
+ hasWaffle: !!canvasElement.querySelector('.cove-waffle-chart')
758
+ })
759
+
760
+ await performAndAssert(
761
+ 'TP5 Gauge to TP5 Waffle',
762
+ getChartTypeState,
763
+ async () => {
764
+ await userEvent.selectOptions(chartTypeSelect, 'TP5 Waffle')
765
+ },
766
+ (before, after) => before.hasGauge !== after.hasGauge && after.hasWaffle
767
+ )
768
+
769
+ await performAndAssert(
770
+ 'TP5 Waffle to TP5 Gauge',
771
+ getChartTypeState,
772
+ async () => {
773
+ await userEvent.selectOptions(chartTypeSelect, 'TP5 Gauge')
774
+ },
775
+ (before, after) => before.hasGauge !== after.hasGauge && after.hasGauge
776
+ )
777
+
778
+ // ============================================================================
779
+ // TEST 2: Title Update
780
+ // Expectation: Callout heading text updates.
781
+ // ============================================================================
782
+ const titleInput = canvas.getByLabelText(/^title$/i, { selector: 'input' }) as HTMLInputElement
783
+ await userEvent.clear(titleInput)
784
+ await userEvent.type(titleInput, 'TP5 Gauge Title Update')
785
+
786
+ await performAndAssert(
787
+ 'TP5 Gauge Title Update',
788
+ () => canvasElement.querySelector('.cdc-callout__heading')?.textContent?.trim() || '',
789
+ async () => {}, // action already performed above
790
+ (before, after) => after === 'TP5 Gauge Title Update'
791
+ )
792
+
793
+ // ============================================================================
794
+ // TEST 3: Show Title Toggle
795
+ // Expectation: Callout heading appears/disappears.
796
+ // ============================================================================
797
+ const showTitleCheckbox = canvasElement.querySelector('input[name="showTitle"]') as HTMLInputElement
798
+ expect(showTitleCheckbox).toBeTruthy()
799
+
800
+ const headingVisible = () => !!canvasElement.querySelector('.cdc-callout__heading')
801
+ const wasVisible = headingVisible()
802
+
803
+ await performAndAssert(
804
+ 'TP5 Gauge Title Toggle',
805
+ headingVisible,
806
+ async () => {
807
+ await userEvent.click(showTitleCheckbox)
808
+ },
809
+ (before, after) => after !== before
810
+ )
811
+
812
+ await performAndAssert(
813
+ 'TP5 Gauge Title Toggle Reset',
814
+ headingVisible,
815
+ async () => {
816
+ await userEvent.click(showTitleCheckbox)
817
+ },
818
+ (before, after) => after === wasVisible
819
+ )
820
+
821
+ // ============================================================================
822
+ // TEST 4: Message Update
823
+ // Expectation: Gauge content text updates.
824
+ // ============================================================================
825
+ const messageTextarea = canvas.getByLabelText(/message/i) as HTMLTextAreaElement
826
+ const newMessage = 'Updated TP5 gauge message text'
827
+ await userEvent.clear(messageTextarea)
828
+ await userEvent.type(messageTextarea, newMessage)
829
+ await waitForTextContent(
830
+ canvasElement.querySelector('.cove-gauge-chart__content .cove-waffle-chart__data--text') as HTMLElement,
831
+ newMessage
832
+ )
833
+
834
+ // ============================================================================
835
+ // TEST 5: Subtext Update
836
+ // Expectation: Subtext text updates.
837
+ // ============================================================================
838
+ const subtextInput = canvas.getByLabelText(/subtext/i) as HTMLInputElement
839
+ const newSubtext = 'Updated TP5 gauge subtext'
840
+ await userEvent.clear(subtextInput)
841
+ await userEvent.type(subtextInput, newSubtext)
842
+ await waitForTextContent(
843
+ canvasElement.querySelector('.cove-gauge-chart .cove-waffle-chart__subtext') as HTMLElement,
844
+ newSubtext
845
+ )
846
+ }
847
+ }
848
+
849
+ /**
850
+ * TP5 GAUGE - DATA SECTION TESTS
851
+ * Tests all functionality within the Data accordion for TP5 Gauge configs.
852
+ */
853
+ export const TP5GaugeDataSectionTests: Story = {
854
+ args: {
855
+ configUrl: '/packages/waffle-chart/examples/tp5-gauge.json',
856
+ isEditor: true
857
+ },
858
+ play: async ({ canvasElement }) => {
859
+ const canvas = within(canvasElement)
860
+ await waitForEditor(canvas)
861
+ await openAccordion(canvas, 'Data')
862
+
863
+ const getPrimaryText = () =>
864
+ canvasElement.querySelector('.cove-waffle-chart__data--primary')?.textContent?.replace(/\s+/g, ' ').trim() || ''
865
+
866
+ // ============================================================================
867
+ // TEST 1: Data Function Change
868
+ // Expectation: Primary value text changes.
869
+ // ============================================================================
870
+ const dataFunctionSelect = canvasElement.querySelector('select[name="dataFunction"]') as HTMLSelectElement
871
+ await waitForOptionsToPopulate(dataFunctionSelect, 2)
872
+ const dataFunctionOptions = Array.from(dataFunctionSelect.options).map(opt => opt.value)
873
+ const nextFunction = dataFunctionOptions.find(opt => opt && opt !== dataFunctionSelect.value)
874
+ expect(nextFunction).toBeTruthy()
875
+
876
+ await performAndAssert(
877
+ 'TP5 Gauge Data Function Change',
878
+ getPrimaryText,
879
+ async () => {
880
+ await userEvent.selectOptions(dataFunctionSelect, nextFunction as string)
881
+ },
882
+ (before, after) => after !== before
883
+ )
884
+
885
+ // ============================================================================
886
+ // TEST 2: Value Description Update
887
+ // Expectation: Primary value text includes new descriptor.
888
+ // ============================================================================
889
+ const valueDescriptionInput = canvasElement.querySelector(
890
+ 'input[name="null-null-valueDescription"]'
891
+ ) as HTMLInputElement
892
+ expect(valueDescriptionInput).toBeTruthy()
893
+ const newDescription = 'out of total'
894
+ await userEvent.clear(valueDescriptionInput)
895
+ await userEvent.type(valueDescriptionInput, newDescription)
896
+ await performAndAssert(
897
+ 'TP5 Gauge Value Description Update',
898
+ getPrimaryText,
899
+ async () => {}, // action already performed above
900
+ (before, after) => after.includes(newDescription)
901
+ )
902
+
903
+ // ============================================================================
904
+ // TEST 3: Denominator Update
905
+ // Expectation: Primary value text changes to include new denominator.
906
+ // ============================================================================
907
+ const denominatorInput = canvasElement.querySelector('input[name="null-null-dataDenom"]') as HTMLInputElement
908
+ expect(denominatorInput).toBeTruthy()
909
+ await performAndAssert(
910
+ 'TP5 Gauge Denominator Update',
911
+ getPrimaryText,
912
+ async () => {
913
+ await userEvent.clear(denominatorInput)
914
+ await userEvent.type(denominatorInput, '250')
915
+ },
916
+ (before, after) => after !== before && after.includes('250')
917
+ )
918
+ }
919
+ }
920
+
921
+ /**
922
+ * TP5 GAUGE - VISUAL SECTION TESTS
923
+ * Tests all functionality within the Visual accordion for TP5 Gauge configs.
924
+ */
925
+ export const TP5GaugeVisualSectionTests: Story = {
926
+ args: {
927
+ configUrl: '/packages/waffle-chart/examples/tp5-gauge.json',
928
+ isEditor: true
929
+ },
930
+ play: async ({ canvasElement }) => {
931
+ const canvas = within(canvasElement)
932
+ await waitForEditor(canvas)
933
+ await openAccordion(canvas, 'Visual')
934
+ await waitForPresence('.cdc-callout', canvasElement)
935
+
936
+ // ============================================================================
937
+ // TEST 1: White Background Toggle
938
+ // Expectation: Callout classes and flag visibility toggle.
939
+ // ============================================================================
940
+ const whiteBackgroundCheckbox = canvas.getByLabelText(/use white background style/i) as HTMLInputElement
941
+ expect(whiteBackgroundCheckbox).toBeTruthy()
942
+
943
+ const getCalloutState = () => {
944
+ const callout = canvasElement.querySelector('.cdc-callout') as HTMLElement
945
+ return {
946
+ classes: callout ? Array.from(callout.classList).sort().join(' ') : '',
947
+ hasFlag: !!canvasElement.querySelector('.cdc-callout__flag')
948
+ }
949
+ }
950
+
951
+ await performAndAssert(
952
+ 'TP5 Gauge White Background Toggle',
953
+ getCalloutState,
954
+ async () => {
955
+ await userEvent.click(whiteBackgroundCheckbox)
956
+ },
957
+ (before, after) => before.classes !== after.classes || before.hasFlag !== after.hasFlag,
958
+ after => {
959
+ if (after.hasFlag) {
960
+ expect(after.classes.includes('cdc-callout--data')).toBe(true)
961
+ } else {
962
+ expect(after.classes.includes('cdc-callout--data')).toBe(false)
963
+ expect(after.classes.includes('dfe-block')).toBe(false)
964
+ }
965
+ }
966
+ )
967
+ }
968
+ }
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import type { Meta, StoryObj } from '@storybook/react-vite'
3
3
 
4
4
  import WaffleChart from '../CdcWaffleChart'
5
+ import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
5
6
 
6
7
  const meta: Meta<typeof WaffleChart> = {
7
8
  title: 'Components/Templates/WaffleChart',
@@ -105,7 +106,10 @@ export const Person: Story = {
105
106
  <>
106
107
  <WaffleChart {...args} />
107
108
  </>
108
- )
109
+ ),
110
+ play: async ({ canvasElement }) => {
111
+ await assertVisualizationRendered(canvasElement)
112
+ }
109
113
  }
110
114
 
111
115
  export const Gauge: Story = {
@@ -186,7 +190,10 @@ export const Gauge: Story = {
186
190
  <>
187
191
  <WaffleChart {...args} />
188
192
  </>
189
- )
193
+ ),
194
+ play: async ({ canvasElement }) => {
195
+ await assertVisualizationRendered(canvasElement)
196
+ }
190
197
  }
191
198
 
192
199
  export const Waffle_Chart_TP5_Style: Story = {
@@ -200,6 +207,9 @@ export const Waffle_Chart_TP5_Style: Story = {
200
207
  '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
208
  }
202
209
  }
210
+ },
211
+ play: async ({ canvasElement }) => {
212
+ await assertVisualizationRendered(canvasElement)
203
213
  }
204
214
  }
205
215
 
@@ -214,6 +224,43 @@ export const Waffle_Chart_TP5_Style_White_Background: Story = {
214
224
  '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
225
  }
216
226
  }
227
+ },
228
+ play: async ({ canvasElement }) => {
229
+ await assertVisualizationRendered(canvasElement)
230
+ }
231
+ }
232
+
233
+ export const TP5_Gauge: Story = {
234
+ args: {
235
+ configUrl: '/packages/waffle-chart/examples/tp5-gauge.json'
236
+ },
237
+ parameters: {
238
+ docs: {
239
+ description: {
240
+ story:
241
+ 'TP5 Gauge - A TP5 callout-style gauge with a blue background, callout flag, and title inside the callout header.'
242
+ }
243
+ }
244
+ },
245
+ play: async ({ canvasElement }) => {
246
+ await assertVisualizationRendered(canvasElement)
247
+ }
248
+ }
249
+
250
+ export const TP5_Gauge_White_Background: Story = {
251
+ args: {
252
+ configUrl: '/packages/waffle-chart/examples/tp5-gauge-white.json'
253
+ },
254
+ parameters: {
255
+ docs: {
256
+ description: {
257
+ story:
258
+ 'TP5 Gauge with White Background - The white background variant of the TP5 gauge features a white callout with a teal border and no callout flag.'
259
+ }
260
+ }
261
+ },
262
+ play: async ({ canvasElement }) => {
263
+ await assertVisualizationRendered(canvasElement)
217
264
  }
218
265
  }
219
266
 
@@ -57,7 +57,8 @@ const EditorPanel = memo(props => {
57
57
  const approvedWaffleChartOptions = [
58
58
  { value: 'Waffle', label: 'Waffle' },
59
59
  { value: 'TP5 Waffle', label: 'TP5 Style Waffle' },
60
- { value: 'Gauge', label: 'Gauge' }
60
+ { value: 'Gauge', label: 'Gauge' },
61
+ { value: 'TP5 Gauge', label: 'TP5 Style Gauge' }
61
62
  ]
62
63
 
63
64
  const editorContent = (
@@ -70,15 +71,6 @@ const EditorPanel = memo(props => {
70
71
  updateField={updateField}
71
72
  options={approvedWaffleChartOptions}
72
73
  />
73
- {config.visualizationType === 'Gauge' && (
74
- <Select
75
- value={config.visualizationSubType}
76
- fieldName='visualizationSubType'
77
- label='Chart Subtype'
78
- updateField={updateField}
79
- options={['Linear']}
80
- />
81
- )}
82
74
  <TextField
83
75
  value={config.title}
84
76
  fieldName='title'
@@ -263,7 +255,7 @@ const EditorPanel = memo(props => {
263
255
  </div>
264
256
  </li>
265
257
  </ul>
266
- {config.visualizationType === 'Gauge' && (
258
+ {(config.visualizationType === 'Gauge' || config.visualizationType === 'TP5 Gauge') && (
267
259
  <>
268
260
  <hr className='cove-accordion__divider' />
269
261
  <div className='cove-accordion__panel-section reverse-labels'>
@@ -344,8 +336,8 @@ const EditorPanel = memo(props => {
344
336
  Add Filter
345
337
  </Button>
346
338
  </Accordion.Section>
347
- <Accordion.Section title='Chart Settings'>
348
- {config.visualizationType !== 'Gauge' && (
339
+ {config.visualizationType !== 'Gauge' && config.visualizationType !== 'TP5 Gauge' && (
340
+ <Accordion.Section title='Chart Settings'>
349
341
  <Select
350
342
  value={config.shape}
351
343
  fieldName='shape'
@@ -353,62 +345,62 @@ const EditorPanel = memo(props => {
353
345
  updateField={updateField}
354
346
  options={['circle', 'square', 'person']}
355
347
  />
356
- )}
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
- />
348
+ {config.visualizationType !== 'TP5 Waffle' && (
349
+ <>
350
+ <div
351
+ className='cove-accordion__panel-row cove-accordion__small-inputs'
352
+ style={{ marginTop: '1rem', marginBottom: '1rem' }}
353
+ >
354
+ <div className='cove-accordion__panel-col'>
355
+ <TextField
356
+ type='number'
357
+ value={config.nodeWidth}
358
+ fieldName='nodeWidth'
359
+ label='Width'
360
+ updateField={updateField}
361
+ />
362
+ </div>
363
+ <div className='cove-accordion__panel-col'>
364
+ <TextField
365
+ type='number'
366
+ value={config.nodeSpacer}
367
+ fieldName='nodeSpacer'
368
+ label='Spacer'
369
+ updateField={updateField}
370
+ />
371
+ </div>
371
372
  </div>
372
- <div className='cove-accordion__panel-col'>
373
- <TextField
374
- type='number'
375
- value={config.nodeSpacer}
376
- fieldName='nodeSpacer'
377
- label='Spacer'
373
+
374
+ <div className='cove-input-group'>
375
+ <Select
376
+ value={config.orientation}
377
+ fieldName='orientation'
378
+ label='Layout'
378
379
  updateField={updateField}
380
+ options={['horizontal', 'vertical']}
379
381
  />
380
382
  </div>
381
- </div>
382
383
 
383
- <div className='cove-input-group'>
384
- <Select
385
- value={config.orientation}
386
- fieldName='orientation'
387
- label='Layout'
388
- updateField={updateField}
389
- options={['horizontal', 'vertical']}
390
- />
391
- </div>
392
-
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>
384
+ <div className='cove-input-group'>
385
+ <label>
386
+ <span className='edit-label column-heading cove-input__label'>Data Point Font Size</span>
387
+ </label>
388
+ <div className='cove-accordion__panel-row cove-accordion__small-inputs align-center'>
389
+ <div className='cove-accordion__panel-col'>
390
+ <TextField type='number' value={config.fontSize} fieldName='fontSize' updateField={updateField} />
391
+ </div>
392
+ <div className='cove-accordion__panel-col' style={{ display: 'flex', alignItems: 'center' }}>
393
+ <label className='accordion__panel-label--muted'> default (50px)</label>
394
+ </div>
403
395
  </div>
404
396
  </div>
405
- </div>
406
- </>
407
- )}
408
- </Accordion.Section>
397
+ </>
398
+ )}
399
+ </Accordion.Section>
400
+ )}
409
401
 
410
402
  {/* Visual section for TP5 style */}
411
- {config.visualizationType === 'TP5 Waffle' && (
403
+ {(config.visualizationType === 'TP5 Waffle' || config.visualizationType === 'TP5 Gauge') && (
412
404
  <Accordion.Section title='Visual'>
413
405
  <CheckBox
414
406
  value={config.visual?.whiteBackground}
@@ -421,7 +413,7 @@ const EditorPanel = memo(props => {
421
413
  )}
422
414
 
423
415
  {/* Visual section for other styles */}
424
- {config.visualizationType !== 'TP5 Waffle' && (
416
+ {config.visualizationType !== 'TP5 Waffle' && config.visualizationType !== 'TP5 Gauge' && (
425
417
  <Accordion.Section title='Visual'>
426
418
  <VisualSection
427
419
  config={config}
@@ -18,7 +18,7 @@
18
18
  justify-items: center;
19
19
  align-items: flex-start;
20
20
 
21
- & > svg {
21
+ &>svg {
22
22
  margin: 0.7em 0;
23
23
  }
24
24
  }
@@ -96,6 +96,7 @@
96
96
  }
97
97
 
98
98
  @at-root {
99
+
99
100
  .cove-waffle-chart.font-small,
100
101
  .cove-gauge-chart.font-small #{&} {
101
102
  .cove-waffle-chart__data--primary {
@@ -135,6 +136,7 @@
135
136
  &.waffle__style--tp5 {
136
137
  .cove-component__content {
137
138
  background: none !important;
139
+ container-type: inline-size;
138
140
  }
139
141
 
140
142
  .cdc-callout {
@@ -167,8 +169,21 @@
167
169
  }
168
170
 
169
171
  .cove-waffle-chart {
172
+ align-items: flex-start;
170
173
  padding: 0;
171
174
  row-gap: 1rem;
175
+ flex-wrap: nowrap;
176
+ }
177
+
178
+ // Container query: wrap when width is less than 576px
179
+ @container (max-width: 576px) {
180
+ .cove-waffle-chart {
181
+ flex-wrap: wrap;
182
+
183
+ .cove-waffle-chart__chart {
184
+ width: 100% !important;
185
+ }
186
+ }
172
187
  }
173
188
 
174
189
  .cove-waffle-chart__chart {
@@ -190,9 +205,11 @@
190
205
  margin-top: 0.5rem;
191
206
  font-size: 1rem;
192
207
  }
208
+
193
209
  .cove-waffle-chart__subtext {
194
210
  font-size: 1rem;
195
211
  }
212
+
196
213
  .cove-waffle-chart__data--primary {
197
214
  font-size: 2rem;
198
215
  color: var(--colors-cyan-60v);
@@ -212,4 +229,120 @@
212
229
  }
213
230
  }
214
231
  }
232
+
233
+ // TP5 Style for Gauge Chart
234
+ &.gauge__style--tp5 {
235
+ .cove-component__content {
236
+ background: none !important;
237
+ container-type: inline-size;
238
+ }
239
+
240
+ .cdc-callout {
241
+ box-shadow: 0 2px 4px rgb(159 159 159 / 10%);
242
+ margin: 0 !important;
243
+ padding: 1.5rem;
244
+ background-color: var(--colors-cyan-10, #eff9fa);
245
+ border: 1px solid var(--colors-cyan-15, #dff2f6);
246
+ position: relative;
247
+ border-radius: 0.25rem;
248
+ gap: 0.5rem;
249
+ }
250
+
251
+ .cdc-callout__flag {
252
+ position: absolute;
253
+ top: -0.25rem;
254
+ right: 1.08rem;
255
+ width: 1.85rem;
256
+ height: auto;
257
+ }
258
+
259
+ .cdc-callout__heading {
260
+ font-family: var(--fonts-nunito) !important;
261
+ width: 100%;
262
+ font-size: 1.1rem;
263
+ }
264
+
265
+ .cove-gauge-chart {
266
+ padding: 0;
267
+ }
268
+
269
+ .cove-gauge-chart__chart {
270
+ width: 100%;
271
+ }
272
+
273
+ .cove-gauge-chart__chart>svg {
274
+ display: block;
275
+ width: 100%;
276
+ }
277
+
278
+ .cove-gauge-chart__body {
279
+ flex-wrap: nowrap;
280
+ gap: 1rem;
281
+ row-gap: 0.5rem;
282
+ margin-bottom: 0.5rem;
283
+ align-items: flex-start; // Align to top instead of center when content varies
284
+ }
285
+
286
+ // Container query: wrap when width is less than 576px
287
+ @container (max-width: 576px) {
288
+ .cove-gauge-chart__body {
289
+ flex-wrap: wrap;
290
+
291
+ .cove-gauge-chart__value-section {
292
+ width: 100%;
293
+ }
294
+ }
295
+ }
296
+
297
+ .cove-gauge-chart__value-section {
298
+ width: auto;
299
+ padding-top: 1px;
300
+ display: flex;
301
+ flex-direction: column;
302
+ justify-content: flex-start;
303
+ }
304
+
305
+ .cove-gauge-chart__content {
306
+ font-size: 1rem;
307
+ min-height: 1rem; // Ensure minimum height even when empty
308
+ }
309
+
310
+ .cove-waffle-chart__data--primary {
311
+ font-size: 2rem;
312
+ color: var(--colors-cyan-60v);
313
+ font-weight: 400;
314
+ line-height: 1;
315
+ }
316
+
317
+ .cove-waffle-chart__data--text {
318
+ margin-top: 0;
319
+ font-size: 1rem;
320
+ }
321
+
322
+ .cove-waffle-chart__subtext {
323
+ font-size: 1rem;
324
+ margin-top: auto;
325
+ }
326
+
327
+ // White background variant (when "Use White Background Style" is checked)
328
+ &.white-background-style {
329
+ .cove-component__content {
330
+ background: white !important;
331
+ }
332
+
333
+ .cdc-callout {
334
+ background: transparent !important;
335
+ border: 1px solid #009ec1 !important;
336
+ box-shadow: 0 2px 4px rgb(159 159 159 / 10%);
337
+ }
338
+ }
339
+ }
215
340
  }
341
+
342
+ // Center gauge value when there's no message (standalone only, not in dashboard rows)
343
+ .type-waffle-chart.gauge__style--tp5:not(.row *) {
344
+ .cove-gauge-chart__body.d-flex.justify-content-center {
345
+ justify-content: center;
346
+ width: 100%;
347
+ }
348
+ }
@@ -3,7 +3,7 @@ import ChartActions from './chart.actions'
3
3
 
4
4
  type ChartState = {
5
5
  config?: Config
6
- container: any
6
+ container: HTMLElement | null
7
7
  coveLoadedHasRan: boolean
8
8
  loading: boolean
9
9
  preview: boolean
@@ -40,6 +40,6 @@ export type Config = {
40
40
  whiteBackground?: boolean
41
41
  }
42
42
  visualizationSubType: 'linear' | ''
43
- visualizationType: 'Gauge' | 'Waffle' | 'TP5 Waffle'
43
+ visualizationType: 'Gauge' | 'Waffle' | 'TP5 Waffle' | 'TP5 Gauge'
44
44
  version: Version
45
45
  }