diff --git a/packages/core/components/Layout/components/Visualization/index.tsx b/packages/core/components/Layout/components/Visualization/index.tsx index 9e68ac01a..255cee8e1 100644 --- a/packages/core/components/Layout/components/Visualization/index.tsx +++ b/packages/core/components/Layout/components/Visualization/index.tsx @@ -104,6 +104,13 @@ const Visualization = forwardRef((props, r } } + if (config.visualizationType === 'TP5 Gauge') { + classes.push('gauge__style--tp5') + if (config.visual?.whiteBackground) { + classes.push('white-background-style') + } + } + classes.push('cove-component', 'waffle-chart') } return classes diff --git a/packages/dashboard/examples/tp5-gauges.json b/packages/dashboard/examples/tp5-gauges.json new file mode 100644 index 000000000..8d0395a0f --- /dev/null +++ b/packages/dashboard/examples/tp5-gauges.json @@ -0,0 +1,196 @@ +{ + "type": "dashboard", + "title": "TP5 Gauge Dashboard Example", + "description": "Three TP5 Gauge charts displaying health metrics", + "data": [ + { + "Category": "Adults", + "Vaccination Rate": "68.5", + "Insured Rate": "87.2", + "Screening Rate": "72.8" + }, + { + "Category": "Seniors", + "Vaccination Rate": "82.3", + "Insured Rate": "95.1", + "Screening Rate": "84.6" + }, + { + "Category": "Youth", + "Vaccination Rate": "54.2", + "Insured Rate": "92.4", + "Screening Rate": "65.3" + } + ], + "dashboard": { + "filters": [] + }, + "rows": [ + [ + { "width": 4, "widget": "gauge1" }, + { "width": 4, "widget": "gauge2" }, + { "width": 4, "widget": "gauge3" } + ] + ], + "visualizations": { + "gauge1": { + "uid": "gauge1", + "type": "waffle-chart", + "title": "Vaccination Coverage", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "of the population is vaccinated against seasonal flu", + "subtext": "Based on 2024 CDC surveillance data across all age groups", + "dataColumn": "Vaccination Rate", + "dataFunction": "Mean (Average)", + "dataConditionalColumn": "", + "dataConditionalOperator": "", + "dataConditionalComparate": "", + "invalidComparate": false, + "customDenom": false, + "dataDenom": "100", + "dataDenomColumn": "", + "dataDenomFunction": "", + "prefix": "", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-blue", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "border": true, + "accent": false, + "background": false, + "hideBackgroundColor": false, + "borderColorTheme": false, + "whiteBackground": false, + "colors": { + "theme-blue": "#005eaa", + "theme-purple": "#712177", + "theme-brown": "#705043", + "theme-teal": "#00695c", + "theme-pink": "#af4448", + "theme-orange": "#bb4d00", + "theme-slate": "#29434e", + "theme-indigo": "#26418f", + "theme-cyan": "#006778", + "theme-green": "#4b830d", + "theme-amber": "#fbab18" + } + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "gauge2": { + "uid": "gauge2", + "type": "waffle-chart", + "title": "Health Insurance Coverage Rate", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "", + "subtext": "", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "dataConditionalColumn": "", + "dataConditionalOperator": "", + "dataConditionalComparate": "", + "invalidComparate": false, + "customDenom": false, + "dataDenom": "100", + "dataDenomColumn": "", + "dataDenomFunction": "", + "prefix": "", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-teal", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "border": true, + "accent": false, + "background": false, + "hideBackgroundColor": false, + "borderColorTheme": false, + "whiteBackground": false, + "colors": { + "theme-blue": "#005eaa", + "theme-purple": "#712177", + "theme-brown": "#705043", + "theme-teal": "#00695c", + "theme-pink": "#af4448", + "theme-orange": "#bb4d00", + "theme-slate": "#29434e", + "theme-indigo": "#26418f", + "theme-cyan": "#006778", + "theme-green": "#4b830d", + "theme-amber": "#fbab18" + } + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "gauge3": { + "uid": "gauge3", + "type": "waffle-chart", + "title": "Cancer Screening Completion", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "Data from National Health Interview Survey 2024", + "dataColumn": "Screening Rate", + "dataFunction": "Mean (Average)", + "dataConditionalColumn": "", + "dataConditionalOperator": "", + "dataConditionalComparate": "", + "invalidComparate": false, + "customDenom": false, + "dataDenom": "100", + "dataDenomColumn": "", + "dataDenomFunction": "", + "prefix": "", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-purple", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "border": true, + "accent": false, + "background": false, + "hideBackgroundColor": false, + "borderColorTheme": false, + "whiteBackground": false, + "colors": { + "theme-blue": "#005eaa", + "theme-purple": "#712177", + "theme-brown": "#705043", + "theme-teal": "#00695c", + "theme-pink": "#af4448", + "theme-orange": "#bb4d00", + "theme-slate": "#29434e", + "theme-indigo": "#26418f", + "theme-cyan": "#006778", + "theme-green": "#4b830d", + "theme-amber": "#fbab18" + } + }, + "showTitle": true, + "overallFontSize": "medium" + } + } +} diff --git a/packages/dashboard/examples/tp5-test.json b/packages/dashboard/examples/tp5-test.json new file mode 100644 index 000000000..769a3473a --- /dev/null +++ b/packages/dashboard/examples/tp5-test.json @@ -0,0 +1,266 @@ +{ + "type": "dashboard", + "title": "TP5 Alignment Test Dashboard", + "description": "Testing alignment of TP5 Waffles, Data Bites, and Gauges", + "data": [ + { + "Category": "Adults", + "Vaccination Rate": "68.5", + "Insured Rate": "87.2", + "Screening Rate": "72.8" + }, + { + "Category": "Seniors", + "Vaccination Rate": "82.3", + "Insured Rate": "95.1", + "Screening Rate": "84.6" + }, + { + "Category": "Youth", + "Vaccination Rate": "54.2", + "Insured Rate": "92.4", + "Screening Rate": "65.3" + } + ], + "dashboard": { + "filters": [] + }, + "rows": [ + [ + { "width": 4, "widget": "waffle1" }, + { "width": 4, "widget": "waffle2" }, + { "width": 4, "widget": "waffle3" } + ], + [ + { "width": 4, "widget": "bite1" }, + { "width": 4, "widget": "bite2" }, + { "width": 4, "widget": "bite3" } + ], + [ + { "width": 4, "widget": "gauge1" }, + { "width": 4, "widget": "gauge2" }, + { "width": 4, "widget": "gauge3" } + ] + ], + "visualizations": { + "waffle1": { + "uid": "waffle1", + "type": "waffle-chart", + "title": "Vaccination Coverage", + "visualizationType": "TP5 Waffle", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "of the population is vaccinated against seasonal flu", + "subtext": "Based on 2024 CDC surveillance data across all age groups", + "dataColumn": "Vaccination Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-blue", + "shape": "square", + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "waffle2": { + "uid": "waffle2", + "type": "waffle-chart", + "title": "Health Insurance Coverage Rate", + "visualizationType": "TP5 Waffle", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-teal", + "shape": "person", + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "waffle3": { + "uid": "waffle3", + "type": "waffle-chart", + "title": "Cancer Screening Completion", + "visualizationType": "TP5 Waffle", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "Data from National Health Interview Survey 2024", + "dataColumn": "Screening Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-purple", + "shape": "circle", + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "gauge1": { + "uid": "gauge1", + "type": "waffle-chart", + "title": "Vaccination Coverage", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "of the population is vaccinated against seasonal flu", + "subtext": "Based on 2024 CDC surveillance data across all age groups", + "dataColumn": "Vaccination Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-blue", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "gauge2": { + "uid": "gauge2", + "type": "waffle-chart", + "title": "Health Insurance Coverage Rate", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "", + "subtext": "", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-teal", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "gauge3": { + "uid": "gauge3", + "type": "waffle-chart", + "title": "Cancer Screening Completion", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "Data from National Health Interview Survey 2024", + "dataColumn": "Screening Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-purple", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "bite1": { + "uid": "bite1", + "type": "data-bite", + "title": "Vaccination Coverage", + "biteStyle": "tp5", + "dataColumn": "Vaccination Rate", + "dataFunction": "Mean (Average)", + "biteBody": "of the population is vaccinated against seasonal flu", + "subtext": "Based on 2024 CDC surveillance data across all age groups", + "dataFormat": { + "roundToPlace": 1, + "commas": true, + "prefix": "", + "suffix": "%" + }, + "theme": "theme-blue", + "visual": { + "hideBackgroundColor": false + } + }, + "bite2": { + "uid": "bite2", + "type": "data-bite", + "title": "Health Insurance Coverage Rate", + "biteStyle": "tp5", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "biteBody": "", + "subtext": "", + "dataFormat": { + "roundToPlace": 1, + "commas": true, + "prefix": "", + "suffix": "%" + }, + "theme": "theme-teal", + "visual": { + "hideBackgroundColor": false + } + }, + "bite3": { + "uid": "bite3", + "type": "data-bite", + "title": "Cancer Screening Completion", + "biteStyle": "tp5", + "dataColumn": "Screening Rate", + "dataFunction": "Mean (Average)", + "biteBody": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "Data from National Health Interview Survey 2024", + "dataFormat": { + "roundToPlace": 1, + "commas": true, + "prefix": "", + "suffix": "%" + }, + "theme": "theme-purple", + "visual": { + "hideBackgroundColor": false + } + } + } +} diff --git a/packages/dashboard/src/_stories/Dashboard.stories.tsx b/packages/dashboard/src/_stories/Dashboard.stories.tsx index 5ade61eda..efb134d98 100644 --- a/packages/dashboard/src/_stories/Dashboard.stories.tsx +++ b/packages/dashboard/src/_stories/Dashboard.stories.tsx @@ -35,6 +35,7 @@ import CascadingDataFilters from './_mock/filter-cascade.json' import ParentChildFilters from './_mock/parent-child-filters.json' import NestedParentChildFilters from './_mock/nested-parent-child-filters.json' import GalleryDataBiteDashboard from './_mock/gallery-data-bite-dashboard.json' +import TP5TestConfig from './_mock/tp5-test.json' // Dashboard Filter Updates for Ascending, Descending, and Custom Order import DashboardFilterAsc from './_mock/dashboard-filter-asc.json' @@ -103,6 +104,13 @@ export const Example_3: Story = { } } +export const TP5_Test_Dashboard: Story = { + args: { + config: TP5TestConfig, + isEditor: false + } +} + export const Bump_Chart_Dashboard: Story = { args: { config: BumpChartConfig, diff --git a/packages/dashboard/src/_stories/_mock/tp5-test.json b/packages/dashboard/src/_stories/_mock/tp5-test.json new file mode 100644 index 000000000..7a7b6f74b --- /dev/null +++ b/packages/dashboard/src/_stories/_mock/tp5-test.json @@ -0,0 +1,267 @@ +{ + "type": "dashboard", + "title": "TP5 Alignment Test Dashboard", + "description": "Testing alignment of TP5 Waffles, Data Bites, and Gauges", + "data": [ + { + "Category": "Adults", + "Vaccination Rate": "68.5", + "Insured Rate": "87.2", + "Screening Rate": "72.8" + }, + { + "Category": "Seniors", + "Vaccination Rate": "82.3", + "Insured Rate": "95.1", + "Screening Rate": "84.6" + }, + { + "Category": "Youth", + "Vaccination Rate": "54.2", + "Insured Rate": "92.4", + "Screening Rate": "65.3" + } + ], + "dashboard": { + "filters": [] + }, + "rows": [ + [ + { "width": 4, "widget": "waffle1" }, + { "width": 4, "widget": "waffle2" }, + { "width": 4, "widget": "waffle3" } + ], + [ + { "width": 4, "widget": "bite1" }, + { "width": 4, "widget": "bite2" }, + { "width": 4, "widget": "bite3" } + ], + [ + { "width": 4, "widget": "gauge1" }, + { "width": 4, "widget": "gauge2" }, + { "width": 4, "widget": "gauge3" } + ] + ], + "visualizations": { + "waffle1": { + "uid": "waffle1", + "type": "waffle-chart", + "title": "Vaccination Coverage", + "visualizationType": "TP5 Waffle", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "of the population is vaccinated against seasonal flu", + "subtext": "Based on 2024 CDC surveillance data across all age groups", + "dataColumn": "Vaccination Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-blue", + "shape": "square", + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "waffle2": { + "uid": "waffle2", + "type": "waffle-chart", + "title": "Health Insurance Coverage Rate", + "visualizationType": "TP5 Waffle", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-teal", + "shape": "person", + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "waffle3": { + "uid": "waffle3", + "type": "waffle-chart", + "title": "Cancer Screening Completion", + "visualizationType": "TP5 Waffle", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "Data from National Health Interview Survey 2024", + "dataColumn": "Screening Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-purple", + "shape": "circle", + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "gauge1": { + "uid": "gauge1", + "type": "waffle-chart", + "title": "Vaccination Coverage", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "of the population is vaccinated against seasonal flu", + "subtext": "Based on 2024 CDC surveillance data across all age groups", + "dataColumn": "Vaccination Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-blue", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "gauge2": { + "uid": "gauge2", + "type": "waffle-chart", + "title": "Health Insurance Coverage Rate", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "", + "subtext": "", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-teal", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "gauge3": { + "uid": "gauge3", + "type": "waffle-chart", + "title": "Cancer Screening Completion", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": false, + "valueDescription": "", + "content": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "Data from National Health Interview Survey 2024", + "dataColumn": "Screening Rate", + "dataFunction": "Mean (Average)", + "customDenom": false, + "dataDenom": "100", + "suffix": "%", + "roundToPlace": "1", + "theme": "theme-purple", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "whiteBackground": false + }, + "showTitle": true, + "overallFontSize": "medium" + }, + "bite1": { + "uid": "bite1", + "type": "data-bite", + "title": "Vaccination Coverage", + "biteStyle": "tp5", + "dataColumn": "Vaccination Rate", + "dataFunction": "Mean (Average)", + "biteBody": "of the population is vaccinated against seasonal flu", + "subtext": "Based on 2024 CDC surveillance data across all age groups", + "dataFormat": { + "roundToPlace": 1, + "commas": true, + "prefix": "", + "suffix": "%" + }, + "theme": "theme-blue", + "visual": { + "hideBackgroundColor": false + } + }, + "bite2": { + "uid": "bite2", + "type": "data-bite", + "title": "Health Insurance Coverage Rate", + "biteStyle": "tp5", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "biteBody": "", + "subtext": "", + "dataFormat": { + "roundToPlace": 1, + "commas": true, + "prefix": "", + "suffix": "%" + }, + "theme": "theme-teal", + "visual": { + "hideBackgroundColor": false + } + }, + "bite3": { + "uid": "bite3", + "type": "data-bite", + "title": "Cancer Screening Completion", + "biteStyle": "tp5", + "dataColumn": "Screening Rate", + "dataFunction": "Mean (Average)", + "biteBody": "completed recommended cancer screenings including mammography, colonoscopy, and cervical cancer screening", + "subtext": "Data from National Health Interview Survey 2024", + "dataFormat": { + "roundToPlace": 1, + "commas": true, + "prefix": "", + "suffix": "%" + }, + "theme": "theme-purple", + "visual": { + "hideBackgroundColor": false + } + } + } +} + diff --git a/packages/dashboard/src/components/VisualizationRow.tsx b/packages/dashboard/src/components/VisualizationRow.tsx index 4822092cb..73369165d 100644 --- a/packages/dashboard/src/components/VisualizationRow.tsx +++ b/packages/dashboard/src/components/VisualizationRow.tsx @@ -103,50 +103,55 @@ const VisualizationRow: React.FC = ({ } }, [toggledRow, row.toggle]) - // Equalize TP5 data bite title heights in the same row - useEffect(() => { - const rowElement = document.querySelector(`[data-row-index="${index}"]`) - if (!rowElement) return + const setupTP5MinHeightEqualizer = (rowElement: Element, itemSelector: string) => { + const items = Array.from(rowElement.querySelectorAll(itemSelector)) as HTMLElement[] + if (items.length <= 1) return undefined - const tp5Titles = Array.from(rowElement.querySelectorAll('.bite__style--tp5 .cdc-callout__heading')) - if (tp5Titles.length <= 1) return // No need to equalize if there's only one or none - - const equalizeTP5Titles = () => { - // Reset heights first - tp5Titles.forEach((title: HTMLElement) => { - title.style.minHeight = '' + const equalizeHeights = () => { + items.forEach(item => { + item.style.minHeight = '' }) - // Calculate max height after reset let maxHeight = 0 - tp5Titles.forEach((title: HTMLElement) => { - const height = title.offsetHeight + items.forEach(item => { + const height = item.offsetHeight if (height > maxHeight) maxHeight = height }) - // Apply max height to all titles if (maxHeight > 0) { - tp5Titles.forEach((title: HTMLElement) => { - title.style.minHeight = `${maxHeight}px` + items.forEach(item => { + item.style.minHeight = `${maxHeight}px` }) } } - // Initial equalization - equalizeTP5Titles() + equalizeHeights() - // Use ResizeObserver to watch for size changes in any of the titles const resizeObserver = new ResizeObserver(() => { - equalizeTP5Titles() + equalizeHeights() }) - // Observe all titles - tp5Titles.forEach(title => { - resizeObserver.observe(title as Element) + items.forEach(item => { + resizeObserver.observe(item) }) + return () => resizeObserver.disconnect() + } + + // Equalize TP5 callout title heights and TP5 gauge message blocks for like visualizations in the same row + useEffect(() => { + const rowElement = document.querySelector(`[data-row-index="${index}"]`) + if (!rowElement) return + + const cleanups = [ + setupTP5MinHeightEqualizer(rowElement, '.bite__style--tp5 .cdc-callout__heading'), + setupTP5MinHeightEqualizer(rowElement, '.waffle__style--tp5 .cdc-callout__heading'), + setupTP5MinHeightEqualizer(rowElement, '.gauge__style--tp5 .cdc-callout__heading'), + setupTP5MinHeightEqualizer(rowElement, '.gauge__style--tp5 .cove-gauge-chart__content') + ].filter(Boolean) as Array<() => void> + return () => { - resizeObserver.disconnect() + cleanups.forEach(cleanup => cleanup()) } }, [index, row, config, filteredDataOverride]) diff --git a/packages/dashboard/src/scss/main.scss b/packages/dashboard/src/scss/main.scss index 2cc3efc43..ef7ad2a09 100644 --- a/packages/dashboard/src/scss/main.scss +++ b/packages/dashboard/src/scss/main.scss @@ -312,8 +312,9 @@ } } - // Ensure Bootstrap rows with TP5 waffle charts stretch columns to equal height - .row:has(.waffle__style--tp5) { + // Ensure Bootstrap rows with TP5 waffle/gauge charts stretch columns to equal height + .row:has(.waffle__style--tp5), + .row:has(.gauge__style--tp5) { display: flex !important; align-items: stretch !important; @@ -346,9 +347,11 @@ } } - // TP5 Waffle Chart adjustments when there are 2+ in a row - .row:has(.waffle__style--tp5):has([class*='col-'] ~ [class*='col-']) { - .waffle__style--tp5 { + // TP5 Waffle/Gauge adjustments when there are 2+ in a row + .row:has(.waffle__style--tp5):has([class*='col-'] ~ [class*='col-']), + .row:has(.gauge__style--tp5):has([class*='col-'] ~ [class*='col-']) { + .waffle__style--tp5, + .gauge__style--tp5 { // Enable flex stretching only in dashboard rows .cove-component__content { height: 100%; diff --git a/packages/waffle-chart/examples/tp5-gauge-white.json b/packages/waffle-chart/examples/tp5-gauge-white.json new file mode 100644 index 000000000..0ce4bf405 --- /dev/null +++ b/packages/waffle-chart/examples/tp5-gauge-white.json @@ -0,0 +1,158 @@ +{ + "title": "TP5 Gauge Chart - White Background", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": true, + "valueDescription": "out of", + "content": "of cases occurred in the home", + "subtext": "Chart subtext or citation", + "orientation": "horizontal", + "data": [ + { + "Insured Rate": "43", + "Coverage Status": "Insured", + "state": "Alabama", + "Year (Good filter option)": "2010", + "link": "", + "Verified": true + }, + { + "Insured Rate": "0", + "Coverage Status": "Uninsured", + "state": "Alaska", + "Year (Good filter option)": "2006", + "link": "", + "Verified": false + }, + { + "Insured Rate": "72.7", + "Coverage Status": "Insured", + "state": "Arizona", + "Year (Good filter option)": "2008", + "link": "#lorem", + "Verified": true + }, + { + "Insured Rate": "78.7", + "Coverage Status": "Insured", + "state": "Arkansas", + "Year (Good filter option)": "2010", + "link": "", + "Verified": true + }, + { + "Insured Rate": "37.2", + "Coverage Status": "Insured", + "state": "California", + "Year (Good filter option)": "2018", + "link": "https://search.cdc.gov/search/?query=California&utf8=%E2%9C%93&affiliate=cdc-main", + "Verified": true + }, + { + "Insured Rate": "50.6", + "Coverage Status": "Insured", + "state": "Colorado", + "Year (Good filter option)": "2014", + "link": "", + "Verified": false + }, + { + "Insured Rate": "83.2", + "Coverage Status": "Insured", + "state": "Connecticut", + "Year (Good filter option)": "2019", + "link": "", + "Verified": true + }, + { + "Insured Rate": "90", + "Coverage Status": "Insured", + "state": "Delaware", + "Year (Good filter option)": "2020", + "link": "", + "Verified": true + }, + { + "Insured Rate": "77.1", + "Coverage Status": "Insured", + "state": "District of Columbia", + "Year (Good filter option)": "2019", + "link": "https://search.cdc.gov/search/index.html?query=Washington+D.C.&sitelimit=&utf8=%E2%9C%93&affiliate=cdc-main", + "Verified": false + }, + { + "Insured Rate": "83", + "Coverage Status": "Insured", + "state": "Florida", + "Year (Good filter option)": "2016", + "link": "", + "Verified": true + }, + { + "Insured Rate": "67.4", + "Coverage Status": "Insured", + "state": "Georgia", + "Year (Good filter option)": "2013", + "link": "", + "Verified": false + } + ], + "filters": [ + { + "columnName": "Year (Good filter option)", + "label": "Year", + "showDropdown": true, + "order": "desc", + "active": true, + "values": [], + "type": "multi-select" + } + ], + "fontSize": "", + "overallFontSize": "medium", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "dataConditionalColumn": "", + "dataConditionalOperator": "", + "dataConditionalComparate": "", + "invalidComparate": false, + "customDenom": false, + "dataDenom": "100", + "dataDenomColumn": "", + "dataDenomFunction": "", + "prefix": "", + "suffix": "%", + "roundToPlace": "0", + "shape": "circle", + "nodeWidth": "10", + "nodeSpacer": "2", + "theme": "theme-blue", + "type": "waffle-chart", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "border": false, + "accent": false, + "background": false, + "hideBackgroundColor": false, + "borderColorTheme": false, + "whiteBackground": true, + "colors": { + "theme-blue": "#005eaa", + "theme-purple": "#712177", + "theme-brown": "#705043", + "theme-teal": "#00695c", + "theme-pink": "#af4448", + "theme-orange": "#bb4d00", + "theme-slate": "#29434e", + "theme-indigo": "#26418f", + "theme-cyan": "#006778", + "theme-green": "#4b830d", + "theme-amber": "#fbab18" + } + }, + "showTitle": true +} diff --git a/packages/waffle-chart/examples/tp5-gauge.json b/packages/waffle-chart/examples/tp5-gauge.json new file mode 100644 index 000000000..ea9280490 --- /dev/null +++ b/packages/waffle-chart/examples/tp5-gauge.json @@ -0,0 +1,158 @@ +{ + "title": "TP5 Gauge Chart", + "visualizationType": "TP5 Gauge", + "visualizationSubType": "linear", + "showPercent": true, + "showDenominator": true, + "valueDescription": "out of", + "content": "of cases occurred in the home", + "subtext": "Chart subtext or citation", + "orientation": "horizontal", + "data": [ + { + "Insured Rate": "43", + "Coverage Status": "Insured", + "state": "Alabama", + "Year (Good filter option)": "2010", + "link": "", + "Verified": true + }, + { + "Insured Rate": "0", + "Coverage Status": "Uninsured", + "state": "Alaska", + "Year (Good filter option)": "2006", + "link": "", + "Verified": false + }, + { + "Insured Rate": "72.7", + "Coverage Status": "Insured", + "state": "Arizona", + "Year (Good filter option)": "2008", + "link": "#lorem", + "Verified": true + }, + { + "Insured Rate": "78.7", + "Coverage Status": "Insured", + "state": "Arkansas", + "Year (Good filter option)": "2010", + "link": "", + "Verified": true + }, + { + "Insured Rate": "37.2", + "Coverage Status": "Insured", + "state": "California", + "Year (Good filter option)": "2018", + "link": "https://search.cdc.gov/search/?query=California&utf8=%E2%9C%93&affiliate=cdc-main", + "Verified": true + }, + { + "Insured Rate": "50.6", + "Coverage Status": "Insured", + "state": "Colorado", + "Year (Good filter option)": "2014", + "link": "", + "Verified": false + }, + { + "Insured Rate": "83.2", + "Coverage Status": "Insured", + "state": "Connecticut", + "Year (Good filter option)": "2019", + "link": "", + "Verified": true + }, + { + "Insured Rate": "90", + "Coverage Status": "Insured", + "state": "Delaware", + "Year (Good filter option)": "2020", + "link": "", + "Verified": true + }, + { + "Insured Rate": "77.1", + "Coverage Status": "Insured", + "state": "District of Columbia", + "Year (Good filter option)": "2019", + "link": "https://search.cdc.gov/search/index.html?query=Washington+D.C.&sitelimit=&utf8=%E2%9C%93&affiliate=cdc-main", + "Verified": false + }, + { + "Insured Rate": "83", + "Coverage Status": "Insured", + "state": "Florida", + "Year (Good filter option)": "2016", + "link": "", + "Verified": true + }, + { + "Insured Rate": "67.4", + "Coverage Status": "Insured", + "state": "Georgia", + "Year (Good filter option)": "2013", + "link": "", + "Verified": false + } + ], + "filters": [ + { + "columnName": "Year (Good filter option)", + "label": "Year", + "showDropdown": true, + "order": "desc", + "active": true, + "values": [], + "type": "multi-select" + } + ], + "fontSize": "", + "overallFontSize": "medium", + "dataColumn": "Insured Rate", + "dataFunction": "Mean (Average)", + "dataConditionalColumn": "", + "dataConditionalOperator": "", + "dataConditionalComparate": "", + "invalidComparate": false, + "customDenom": false, + "dataDenom": "100", + "dataDenomColumn": "", + "dataDenomFunction": "", + "prefix": "", + "suffix": "%", + "roundToPlace": "0", + "shape": "circle", + "nodeWidth": "10", + "nodeSpacer": "2", + "theme": "theme-blue", + "type": "waffle-chart", + "gauge": { + "height": 35, + "width": "100%" + }, + "visual": { + "border": true, + "accent": false, + "background": false, + "hideBackgroundColor": false, + "borderColorTheme": false, + "whiteBackground": false, + "colors": { + "theme-blue": "#005eaa", + "theme-purple": "#712177", + "theme-brown": "#705043", + "theme-teal": "#00695c", + "theme-pink": "#af4448", + "theme-orange": "#bb4d00", + "theme-slate": "#29434e", + "theme-indigo": "#26418f", + "theme-cyan": "#006778", + "theme-green": "#4b830d", + "theme-amber": "#fbab18" + } + }, + "showTitle": true +} diff --git a/packages/waffle-chart/src/CdcWaffleChart.tsx b/packages/waffle-chart/src/CdcWaffleChart.tsx index b1b0423be..0edf5faea 100644 --- a/packages/waffle-chart/src/CdcWaffleChart.tsx +++ b/packages/waffle-chart/src/CdcWaffleChart.tsx @@ -456,34 +456,107 @@ const WaffleChart = ({ config, isEditor, link = '', showConfigConfirm, updateCon )} {config.newViz && showConfigConfirm && }
- {config.visualizationType === 'Gauge' && ( + {(config.visualizationType === 'Gauge' || config.visualizationType === 'TP5 Gauge') && (
-
- {prefix ? prefix : ' '} - {config.showPercent ? dataPercentage : waffleNumerator} - {suffix ? suffix + ' ' : ' '} {config.valueDescription}{' '} - {config.showDenominator && waffleDenominator ? waffleDenominator : ' '} -
-
{parse(content)}
- - - - - - -
{parse(subtext)}
+ {config.visualizationType === 'TP5 Gauge' ? ( + <> +
+
+
+ {prefix ? prefix : ' '} + {config.showPercent ? dataPercentage : waffleNumerator} + {suffix ? suffix + ' ' : ' '} {config.valueDescription}{' '} + {config.showDenominator && waffleDenominator ? waffleDenominator : ' '} +
+
+
+ {content ? ( +
{parse(content)}
+ ) : ( + + )} +
+
+ + + + + + + {subtext && ( +
{parse(subtext)}
+ )} + + ) : ( + <> +
+ {prefix ? prefix : ' '} + {config.showPercent ? dataPercentage : waffleNumerator} + {suffix ? suffix + ' ' : ' '} {config.valueDescription}{' '} + {config.showDenominator && waffleDenominator ? waffleDenominator : ' '} +
+
{parse(content)}
+ + + + + + +
{parse(subtext)}
+ + )}
)} - {config.visualizationType !== 'Gauge' && ( + {config.visualizationType !== 'Gauge' && config.visualizationType !== 'TP5 Gauge' && (
)} -
{parse(content)}
+ {content &&
{parse(content)}
} {subtext &&
{parse(subtext)}
}
@@ -517,14 +590,14 @@ const WaffleChart = ({ config, isEditor, link = '', showConfigConfirm, updateCon ) // TP5 Style: render with callout wrapper inside cove-component__content - if (config.visualizationType === 'TP5 Waffle') { + if (config.visualizationType === 'TP5 Waffle' || config.visualizationType === 'TP5 Gauge') { const calloutClasses = ['cdc-callout', 'd-flex', 'flex-column'] if (!config.visual?.whiteBackground) { calloutClasses.push('dfe-block', 'cdc-callout--data') } return ( -
+
{!config.visual?.whiteBackground && ( diff --git a/packages/waffle-chart/src/_stories/WaffleChart.Editor.stories.tsx b/packages/waffle-chart/src/_stories/WaffleChart.Editor.stories.tsx index 3d908402c..cd564cb87 100644 --- a/packages/waffle-chart/src/_stories/WaffleChart.Editor.stories.tsx +++ b/packages/waffle-chart/src/_stories/WaffleChart.Editor.stories.tsx @@ -729,3 +729,240 @@ export const VisualSectionTests: Story = { ) } } + +/** + * TP5 GAUGE - GENERAL SECTION TESTS + * Tests all functionality within the General accordion for TP5 Gauge configs. + */ +export const TP5GaugeGeneralSectionTests: Story = { + args: { + configUrl: '/packages/waffle-chart/examples/tp5-gauge.json', + isEditor: true + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement) + await waitForEditor(canvas) + await openAccordion(canvas, 'General') + await waitForPresence('.cdc-callout', canvasElement) + + // ============================================================================ + // TEST 1: Chart Type Change (TP5 Gauge <-> TP5 Waffle) + // Expectation: Gauge container swaps with waffle container. + // ============================================================================ + const chartTypeSelect = canvas.getByLabelText(/chart type/i) as HTMLSelectElement + expect(chartTypeSelect).toBeTruthy() + + const getChartTypeState = () => ({ + hasGauge: !!canvasElement.querySelector('.cove-gauge-chart'), + hasWaffle: !!canvasElement.querySelector('.cove-waffle-chart') + }) + + await performAndAssert( + 'TP5 Gauge to TP5 Waffle', + getChartTypeState, + async () => { + await userEvent.selectOptions(chartTypeSelect, 'TP5 Waffle') + }, + (before, after) => before.hasGauge !== after.hasGauge && after.hasWaffle + ) + + await performAndAssert( + 'TP5 Waffle to TP5 Gauge', + getChartTypeState, + async () => { + await userEvent.selectOptions(chartTypeSelect, 'TP5 Gauge') + }, + (before, after) => before.hasGauge !== after.hasGauge && after.hasGauge + ) + + // ============================================================================ + // TEST 2: Title Update + // Expectation: Callout heading text updates. + // ============================================================================ + const titleInput = canvas.getByLabelText(/^title$/i, { selector: 'input' }) as HTMLInputElement + await userEvent.clear(titleInput) + await userEvent.type(titleInput, 'TP5 Gauge Title Update') + + await performAndAssert( + 'TP5 Gauge Title Update', + () => canvasElement.querySelector('.cdc-callout__heading')?.textContent?.trim() || '', + async () => {}, // action already performed above + (before, after) => after === 'TP5 Gauge Title Update' + ) + + // ============================================================================ + // TEST 3: Show Title Toggle + // Expectation: Callout heading appears/disappears. + // ============================================================================ + const showTitleCheckbox = canvasElement.querySelector('input[name="showTitle"]') as HTMLInputElement + expect(showTitleCheckbox).toBeTruthy() + + const headingVisible = () => !!canvasElement.querySelector('.cdc-callout__heading') + const wasVisible = headingVisible() + + await performAndAssert( + 'TP5 Gauge Title Toggle', + headingVisible, + async () => { + await userEvent.click(showTitleCheckbox) + }, + (before, after) => after !== before + ) + + await performAndAssert( + 'TP5 Gauge Title Toggle Reset', + headingVisible, + async () => { + await userEvent.click(showTitleCheckbox) + }, + (before, after) => after === wasVisible + ) + + // ============================================================================ + // TEST 4: Message Update + // Expectation: Gauge content text updates. + // ============================================================================ + const messageTextarea = canvas.getByLabelText(/message/i) as HTMLTextAreaElement + const newMessage = 'Updated TP5 gauge message text' + await userEvent.clear(messageTextarea) + await userEvent.type(messageTextarea, newMessage) + await waitForTextContent( + canvasElement.querySelector('.cove-gauge-chart__content .cove-waffle-chart__data--text') as HTMLElement, + newMessage + ) + + // ============================================================================ + // TEST 5: Subtext Update + // Expectation: Subtext text updates. + // ============================================================================ + const subtextInput = canvas.getByLabelText(/subtext/i) as HTMLInputElement + const newSubtext = 'Updated TP5 gauge subtext' + await userEvent.clear(subtextInput) + await userEvent.type(subtextInput, newSubtext) + await waitForTextContent( + canvasElement.querySelector('.cove-gauge-chart .cove-waffle-chart__subtext') as HTMLElement, + newSubtext + ) + } +} + +/** + * TP5 GAUGE - DATA SECTION TESTS + * Tests all functionality within the Data accordion for TP5 Gauge configs. + */ +export const TP5GaugeDataSectionTests: Story = { + args: { + configUrl: '/packages/waffle-chart/examples/tp5-gauge.json', + isEditor: true + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement) + await waitForEditor(canvas) + await openAccordion(canvas, 'Data') + + const getPrimaryText = () => + canvasElement.querySelector('.cove-waffle-chart__data--primary')?.textContent?.replace(/\s+/g, ' ').trim() || '' + + // ============================================================================ + // TEST 1: Data Function Change + // Expectation: Primary value text changes. + // ============================================================================ + const dataFunctionSelect = canvasElement.querySelector('select[name="dataFunction"]') as HTMLSelectElement + await waitForOptionsToPopulate(dataFunctionSelect, 2) + const dataFunctionOptions = Array.from(dataFunctionSelect.options).map(opt => opt.value) + const nextFunction = dataFunctionOptions.find(opt => opt && opt !== dataFunctionSelect.value) + expect(nextFunction).toBeTruthy() + + await performAndAssert( + 'TP5 Gauge Data Function Change', + getPrimaryText, + async () => { + await userEvent.selectOptions(dataFunctionSelect, nextFunction as string) + }, + (before, after) => after !== before + ) + + // ============================================================================ + // TEST 2: Value Description Update + // Expectation: Primary value text includes new descriptor. + // ============================================================================ + const valueDescriptionInput = canvasElement.querySelector( + 'input[name="null-null-valueDescription"]' + ) as HTMLInputElement + expect(valueDescriptionInput).toBeTruthy() + const newDescription = 'out of total' + await userEvent.clear(valueDescriptionInput) + await userEvent.type(valueDescriptionInput, newDescription) + await performAndAssert( + 'TP5 Gauge Value Description Update', + getPrimaryText, + async () => {}, // action already performed above + (before, after) => after.includes(newDescription) + ) + + // ============================================================================ + // TEST 3: Denominator Update + // Expectation: Primary value text changes to include new denominator. + // ============================================================================ + const denominatorInput = canvasElement.querySelector('input[name="null-null-dataDenom"]') as HTMLInputElement + expect(denominatorInput).toBeTruthy() + await performAndAssert( + 'TP5 Gauge Denominator Update', + getPrimaryText, + async () => { + await userEvent.clear(denominatorInput) + await userEvent.type(denominatorInput, '250') + }, + (before, after) => after !== before && after.includes('250') + ) + } +} + +/** + * TP5 GAUGE - VISUAL SECTION TESTS + * Tests all functionality within the Visual accordion for TP5 Gauge configs. + */ +export const TP5GaugeVisualSectionTests: Story = { + args: { + configUrl: '/packages/waffle-chart/examples/tp5-gauge.json', + isEditor: true + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement) + await waitForEditor(canvas) + await openAccordion(canvas, 'Visual') + await waitForPresence('.cdc-callout', canvasElement) + + // ============================================================================ + // TEST 1: White Background Toggle + // Expectation: Callout classes and flag visibility toggle. + // ============================================================================ + const whiteBackgroundCheckbox = canvas.getByLabelText(/use white background style/i) as HTMLInputElement + expect(whiteBackgroundCheckbox).toBeTruthy() + + const getCalloutState = () => { + const callout = canvasElement.querySelector('.cdc-callout') as HTMLElement + return { + classes: callout ? Array.from(callout.classList).sort().join(' ') : '', + hasFlag: !!canvasElement.querySelector('.cdc-callout__flag') + } + } + + await performAndAssert( + 'TP5 Gauge White Background Toggle', + getCalloutState, + async () => { + await userEvent.click(whiteBackgroundCheckbox) + }, + (before, after) => before.classes !== after.classes || before.hasFlag !== after.hasFlag, + after => { + if (after.hasFlag) { + expect(after.classes.includes('cdc-callout--data')).toBe(true) + } else { + expect(after.classes.includes('cdc-callout--data')).toBe(false) + expect(after.classes.includes('dfe-block')).toBe(false) + } + } + ) + } +} diff --git a/packages/waffle-chart/src/_stories/WaffleChart.stories.tsx b/packages/waffle-chart/src/_stories/WaffleChart.stories.tsx index b6a5b0210..3bba1e0ba 100644 --- a/packages/waffle-chart/src/_stories/WaffleChart.stories.tsx +++ b/packages/waffle-chart/src/_stories/WaffleChart.stories.tsx @@ -217,4 +217,32 @@ export const Waffle_Chart_TP5_Style_White_Background: Story = { } } +export const TP5_Gauge: Story = { + args: { + configUrl: '/packages/waffle-chart/examples/tp5-gauge.json' + }, + parameters: { + docs: { + description: { + story: + 'TP5 Gauge - A TP5 callout-style gauge with a blue background, callout flag, and title inside the callout header.' + } + } + } +} + +export const TP5_Gauge_White_Background: Story = { + args: { + configUrl: '/packages/waffle-chart/examples/tp5-gauge-white.json' + }, + parameters: { + docs: { + description: { + story: + '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.' + } + } + } +} + export default meta diff --git a/packages/waffle-chart/src/components/EditorPanel.jsx b/packages/waffle-chart/src/components/EditorPanel.jsx index 025fa017e..8cdd1ca0e 100644 --- a/packages/waffle-chart/src/components/EditorPanel.jsx +++ b/packages/waffle-chart/src/components/EditorPanel.jsx @@ -57,7 +57,8 @@ const EditorPanel = memo(props => { const approvedWaffleChartOptions = [ { value: 'Waffle', label: 'Waffle' }, { value: 'TP5 Waffle', label: 'TP5 Style Waffle' }, - { value: 'Gauge', label: 'Gauge' } + { value: 'Gauge', label: 'Gauge' }, + { value: 'TP5 Gauge', label: 'TP5 Style Gauge' } ] const editorContent = ( @@ -70,15 +71,6 @@ const EditorPanel = memo(props => { updateField={updateField} options={approvedWaffleChartOptions} /> - {config.visualizationType === 'Gauge' && ( - { updateField={updateField} options={['circle', 'square', 'person']} /> - )} - {config.visualizationType !== 'Gauge' && config.visualizationType !== 'TP5 Waffle' && ( - <> -
-
- + {config.visualizationType !== 'TP5 Waffle' && ( + <> +
+
+ +
+
+ +
-
- + -
- -
- -
-
- -
-
- +
+ +
+
+ +
+
+ +
-
- - )} - + + )} + + )} {/* Visual section for TP5 style */} - {config.visualizationType === 'TP5 Waffle' && ( + {(config.visualizationType === 'TP5 Waffle' || config.visualizationType === 'TP5 Gauge') && ( { )} {/* Visual section for other styles */} - {config.visualizationType !== 'TP5 Waffle' && ( + {config.visualizationType !== 'TP5 Waffle' && config.visualizationType !== 'TP5 Gauge' && ( svg { + display: block; + width: 100%; + } + + .cove-gauge-chart__body { + flex-wrap: nowrap; + gap: 1rem; + row-gap: 0.5rem; + margin-bottom: 0.5rem; + align-items: flex-start; // Align to top instead of center when content varies + } + + // Container query: wrap when width is less than 576px + @container (max-width: 576px) { + .cove-gauge-chart__body { + flex-wrap: wrap; + .cove-gauge-chart__value-section { + width: 100%; + } + } + } + + .cove-gauge-chart__value-section { + width: auto; + padding-top: 1px; + display: flex; + flex-direction: column; + justify-content: flex-start; + } + + .cove-gauge-chart__content { + font-size: 1rem; + min-height: 1rem; // Ensure minimum height even when empty + } + + .cove-waffle-chart__data--primary { + font-size: 2rem; + color: var(--colors-cyan-60v); + font-weight: 400; + line-height: 1; + } + + .cove-waffle-chart__data--text { + margin-top: 0; + font-size: 1rem; + } + + .cove-waffle-chart__subtext { + font-size: 1rem; + margin-top: auto; + } + + // White background variant (when "Use White Background Style" is checked) + &.white-background-style { + .cove-component__content { + background: white !important; + } + + .cdc-callout { + background: transparent !important; + border: 1px solid #009ec1 !important; + box-shadow: 0 2px 4px rgb(159 159 159 / 10%); + } + } + } +} + +// Center gauge value when there's no message (standalone only, not in dashboard rows) +.type-waffle-chart.gauge__style--tp5:not(.row *) { + .cove-gauge-chart__body.d-flex.justify-content-center { + justify-content: center; + width: 100%; + } } diff --git a/packages/waffle-chart/src/types/Config.ts b/packages/waffle-chart/src/types/Config.ts index 4717bd5b6..de4114c6f 100644 --- a/packages/waffle-chart/src/types/Config.ts +++ b/packages/waffle-chart/src/types/Config.ts @@ -40,6 +40,6 @@ export type Config = { whiteBackground?: boolean } visualizationSubType: 'linear' | '' - visualizationType: 'Gauge' | 'Waffle' | 'TP5 Waffle' + visualizationType: 'Gauge' | 'Waffle' | 'TP5 Waffle' | 'TP5 Gauge' version: Version }