@cdc/chart 4.26.3 → 4.26.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONFIG.md +169 -0
- package/README.md +42 -17
- package/dist/cdcchart.js +34725 -33730
- package/examples/feature/bar/additional-column-tooltip.json +3 -3
- package/examples/feature/deviation/planet-deviation-config.json +2 -2
- package/examples/feature/paired-bar/paired-bar-example.json +2 -2
- package/examples/feature/tests-case-rate/case-rate-example-config.json +2 -2
- package/examples/feature/tests-covid/covid-confidence-example-config.json +2 -2
- package/examples/feature/tests-covid/covid-example-config.json +2 -2
- package/examples/feature/tests-cutoff/cutoff-example-config.json +2 -2
- package/examples/feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json +2 -2
- package/examples/metadata-variables.json +1 -1
- package/examples/minimal-example.json +24 -0
- package/examples/private/test2.json +35012 -0
- package/package.json +4 -4
- package/src/CdcChartComponent.tsx +9 -6
- package/src/_stories/{Chart.HTMLInDataTable.stories.tsx → Chart.HTMLInDataTable.smoke.stories.tsx} +10 -0
- package/src/_stories/Chart.Minimal.smoke.stories.tsx +25 -0
- package/src/_stories/{Chart.SmallMultiples.stories.tsx → Chart.SmallMultiples.smoke.stories.tsx} +17 -1
- package/src/_stories/{Chart.stories.tsx → Chart.smoke.stories.tsx} +12 -0
- package/src/_stories/{Chart.tooltip.stories.tsx → Chart.tooltip.smoke.stories.tsx} +68 -0
- package/src/_stories/ChartBar.Editor.stories.tsx +88 -85
- package/src/_stories/ChartEditor.Editor.stories.tsx +23 -0
- package/src/_stories/ChartLine.DashedDates.smoke.stories.tsx +23 -0
- package/src/_stories/_mock/line_chart_dashed_dates.json +276 -0
- package/src/_stories/_mock/paired-bar-abbr.json +1 -1
- package/src/_stories/_mock/paired-bar.json +1 -1
- package/src/components/Annotations/components/AnnotationDraggable.tsx +1 -1
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +10 -2
- package/src/components/Axis/BottomAxis.tsx +1 -1
- package/src/components/Axis/LeftAxis.tsx +2 -4
- package/src/components/Axis/LeftAxisGridlines.tsx +1 -3
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +9 -5
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +9 -5
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +9 -5
- package/src/components/BarChart/components/BarChart.Vertical.tsx +9 -6
- package/src/components/BarChart/components/BarChart.tsx +2 -6
- package/src/components/BarChart/helpers/useBarChart.ts +1 -1
- package/src/components/BoxPlot/BoxPlot.Vertical.tsx +3 -3
- package/src/components/EditorPanel/EditorPanel.tsx +633 -908
- package/src/components/EditorPanel/EditorPanelContext.ts +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +216 -165
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +168 -116
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +154 -109
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +12 -26
- package/src/components/EditorPanel/useEditorPermissions.ts +1 -10
- package/src/components/Forecasting/Forecasting.tsx +2 -2
- package/src/components/HorizonChart/HorizonChart.tsx +10 -2
- package/src/components/HoverLine/HoverLine.tsx +6 -8
- package/src/components/Legend/Legend.Component.tsx +4 -4
- package/src/components/Legend/LegendGroup/LegendGroup.styles.css +5 -0
- package/src/components/Legend/LegendGroup/LegendGroup.tsx +3 -1
- package/src/components/Legend/helpers/index.ts +0 -2
- package/src/components/LineChart/LineChartProps.ts +1 -0
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +3 -2
- package/src/components/LineChart/index.tsx +11 -4
- package/src/components/LinearChart/VisualizationRenderer.tsx +11 -1
- package/src/components/LinearChart/tests/LinearChart.test.tsx +147 -0
- package/src/components/LinearChart.tsx +98 -41
- package/src/components/PairedBarChart.jsx +2 -2
- package/src/components/PieChart/PieChart.tsx +11 -9
- package/src/components/Regions/components/Regions.tsx +30 -20
- package/src/components/ScatterPlot/ScatterPlot.jsx +19 -17
- package/src/components/SmallMultiples/SmallMultipleTile.tsx +1 -0
- package/src/components/Sparkline/components/SparkLine.tsx +1 -1
- package/src/components/WarmingStripes/WarmingStripes.tsx +5 -3
- package/src/data/initial-state.js +1 -0
- package/src/helpers/calculateLeftYAxisWidth.ts +193 -0
- package/src/helpers/tests/tooltipHelpers.test.ts +151 -0
- package/src/helpers/tooltipHelpers.ts +176 -0
- package/src/hooks/useHighlightedBars.ts +9 -16
- package/src/hooks/useProgrammaticTooltip.ts +16 -2
- package/src/hooks/useSmallMultipleSynchronization.ts +3 -4
- package/src/hooks/useTooltip.tsx +167 -38
- package/src/test/CdcChart.test.jsx +24 -0
- package/src/types/ChartConfig.ts +1 -0
- package/LICENSE +0 -201
- package/examples/chart-regression-2.json +0 -2360
- package/examples/feature/__data__/age-adjusted-rates.json +0 -1486
- package/examples/feature/__data__/city-temperature.json +0 -2198
- package/examples/feature/bar/Barchart_with_negative.json +0 -34
- package/examples/feature/boxplot/box-plot-data.json +0 -71
- package/examples/feature/boxplot/boxplot-data.json +0 -156
- package/examples/feature/combo/combochart-categories_are_numbers .json +0 -18
- package/examples/feature/forest-plot/log.json +0 -26
- package/examples/feature/tests-date-exclusions/date-exclusions-data.json +0 -162
- package/examples/region-issue.json +0 -2065
- package/examples/xaxis.json +0 -493
- /package/examples/{data → __data__}/data-with-metadata.json +0 -0
- /package/examples/feature/bar/{tall-data.json → __data__/tall-data.json} +0 -0
- /package/examples/feature/deviation/{planet-deviation-data.json → __data__/planet-deviation-data.json} +0 -0
- /package/examples/feature/paired-bar/{paired-bar-data.json → __data__/paired-bar-data.json} +0 -0
- /package/examples/feature/paired-bar/{paired-bar-formatted.json → __data__/paired-bar-formatted.json} +0 -0
- /package/examples/feature/tests-case-rate/{case-rate-example-data.json → __data__/case-rate-example-data.json} +0 -0
- /package/examples/feature/tests-covid/{covid-example-data-confidence.json → __data__/covid-example-data-confidence.json} +0 -0
- /package/examples/feature/tests-covid/{covid-example-data.json → __data__/covid-example-data.json} +0 -0
- /package/examples/feature/tests-cutoff/{cutoff-example-data.json → __data__/cutoff-example-data.json} +0 -0
- /package/examples/feature/tests-non-numerics/{planet-example-data-nonnumeric.json → __data__/planet-example-data-nonnumeric.json} +0 -0
- /package/src/_stories/{Chart.Anchors.stories.tsx → Chart.Anchors.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.BoxPlot.stories.tsx → Chart.BoxPlot.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.CI.stories.tsx → Chart.CI.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Combo.stories.tsx → Chart.Combo.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.CustomColors.stories.tsx → Chart.CustomColors.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Defaults.stories.tsx → Chart.Defaults.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.DynamicSeries.stories.tsx → Chart.DynamicSeries.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Filters.stories.tsx → Chart.Filters.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Forecast.stories.tsx → Chart.Forecast.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Legend.Gradient.stories.tsx → Chart.Legend.Gradient.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Patterns.stories.tsx → Chart.Patterns.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.PreserveDecimals.stories.tsx → Chart.PreserveDecimals.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Regions.Categorical.stories.tsx → Chart.Regions.Categorical.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Regions.DateScale.stories.tsx → Chart.Regions.DateScale.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.Regions.DateTimeScale.stories.tsx → Chart.Regions.DateTimeScale.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.ScatterPlot.stories.tsx → Chart.ScatterPlot.smoke.stories.tsx} +0 -0
- /package/src/_stories/{Chart.SmallestLeftAxisMax.stories.tsx → Chart.SmallestLeftAxisMax.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartAnnotation.stories.tsx → ChartAnnotation.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartAxisLabels.stories.tsx → ChartAxisLabels.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartAxisTitles.stories.tsx → ChartAxisTitles.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartBrush.Matrix.Continuous.stories.tsx → ChartBrush.Matrix.Continuous.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartBrush.Matrix.Date.stories.tsx → ChartBrush.Matrix.Date.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartBrush.Matrix.DateTime.stories.tsx → ChartBrush.Matrix.DateTime.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartBrush.stories.tsx → ChartBrush.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartLine.QuadrantAngles.stories.tsx → ChartLine.QuadrantAngles.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartLine.Suppression.stories.tsx → ChartLine.Suppression.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartLine.Symbols.stories.tsx → ChartLine.Symbols.smoke.stories.tsx} +0 -0
- /package/src/_stories/{ChartPrefixSuffix.stories.tsx → ChartPrefixSuffix.smoke.stories.tsx} +0 -0
- /package/src/_stories/{TechAdoptionWithLinks.stories.tsx → TechAdoptionWithLinks.smoke.stories.tsx} +0 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/chart",
|
|
3
|
-
"version": "4.26.
|
|
3
|
+
"version": "4.26.4",
|
|
4
4
|
"description": "React component for visualizing tabular data in various types of charts",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Matthew Pallansch <mpallansch@adittech.com>",
|
|
7
7
|
"bugs": "https://github.com/CDCgov/cdc-open-viz/issues",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@cdc/core": "^4.26.
|
|
9
|
+
"@cdc/core": "^4.26.4",
|
|
10
10
|
"@hello-pangea/dnd": "^16.2.0",
|
|
11
11
|
"@react-spring/web": "^9.7.5",
|
|
12
12
|
"@rollup/plugin-dsv": "^3.0.2",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"d3-format": "^3.1.2",
|
|
35
35
|
"d3-sankey": "^0.12.3",
|
|
36
36
|
"d3-time-format": "^4.1.0",
|
|
37
|
-
"dompurify": "^3.
|
|
37
|
+
"dompurify": "^3.4.0",
|
|
38
38
|
"html-react-parser": "^5.2.3",
|
|
39
39
|
"js-base64": "^2.5.2",
|
|
40
40
|
"lodash": "^4.17.23",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@types/d3-sankey": "^0.12.4",
|
|
57
57
|
"@types/d3-time-format": "^4.0.3"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "9062881d50c824ee6cdd71868bafd016a5e5694d",
|
|
60
60
|
"main": "dist/cdcchart",
|
|
61
61
|
"moduleName": "CdcChart",
|
|
62
62
|
"peerDependencies": {
|
|
@@ -540,7 +540,6 @@ const CdcChart: React.FC<CdcChartProps> = ({
|
|
|
540
540
|
...horizontalYAxisSource,
|
|
541
541
|
label: runtimeYAxisLabel ?? horizontalYAxisSource?.label
|
|
542
542
|
}
|
|
543
|
-
newConfig.runtime.yAxis.labelOffset *= -1
|
|
544
543
|
|
|
545
544
|
newConfig.runtime.horizontal = false
|
|
546
545
|
newConfig.orientation = 'horizontal'
|
|
@@ -1304,7 +1303,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
|
|
|
1304
1303
|
}
|
|
1305
1304
|
bodySubtext={
|
|
1306
1305
|
processedDescription && config.visualizationType !== 'Spark Line' ? (
|
|
1307
|
-
<div className={getChartSubTextClasses().join(' ')}>{parse(processedDescription)}</div>
|
|
1306
|
+
<div className={`cove-prose ${getChartSubTextClasses().join(' ')}`}>{parse(processedDescription)}</div>
|
|
1308
1307
|
) : null
|
|
1309
1308
|
}
|
|
1310
1309
|
bodyFooter={
|
|
@@ -1391,13 +1390,17 @@ const CdcChart: React.FC<CdcChartProps> = ({
|
|
|
1391
1390
|
)}
|
|
1392
1391
|
{visibleAnnotations.length > 0 && <Annotation.Dropdown />}
|
|
1393
1392
|
{processedLegacyFootnotes && (
|
|
1394
|
-
<section className='footnotes pt-2 mt-4'>{parse(processedLegacyFootnotes)}</section>
|
|
1393
|
+
<section className='footnotes cove-prose pt-2 mt-4'>{parse(processedLegacyFootnotes)}</section>
|
|
1395
1394
|
)}
|
|
1396
1395
|
</>
|
|
1397
1396
|
}
|
|
1398
1397
|
header={isTp5Treatment ? null : chartTitle}
|
|
1399
1398
|
messageIsIntroText={config.visualizationType !== 'Spark Line' && !!processedIntroText}
|
|
1400
|
-
message={
|
|
1399
|
+
message={
|
|
1400
|
+
config.visualizationType !== 'Spark Line' && processedIntroText ? (
|
|
1401
|
+
<div className='cove-prose'>{parse(processedIntroText)}</div>
|
|
1402
|
+
) : null
|
|
1403
|
+
}
|
|
1401
1404
|
footer={
|
|
1402
1405
|
<FootnotesStandAlone
|
|
1403
1406
|
config={configObj.footnotes}
|
|
@@ -1521,7 +1524,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
|
|
|
1521
1524
|
interactionLabel={interactionLabel}
|
|
1522
1525
|
/>
|
|
1523
1526
|
{processedIntroText && (
|
|
1524
|
-
<section className='introText' style={{ padding: '0px 0 35px' }}>
|
|
1527
|
+
<section className='introText cove-prose' style={{ padding: '0px 0 35px' }}>
|
|
1525
1528
|
{parse(processedIntroText)}
|
|
1526
1529
|
</section>
|
|
1527
1530
|
)}
|
|
@@ -1529,7 +1532,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
|
|
|
1529
1532
|
<ParentSize>{parent => <SparkLine width={parent.width} height={parent.height} />}</ParentSize>
|
|
1530
1533
|
</div>
|
|
1531
1534
|
{processedDescription && (
|
|
1532
|
-
<div className='subtext' style={{ padding: '35px 0 1.5rem' }}>
|
|
1535
|
+
<div className='subtext cove-prose' style={{ padding: '35px 0 1.5rem' }}>
|
|
1533
1536
|
{parse(processedDescription)}
|
|
1534
1537
|
</div>
|
|
1535
1538
|
)}
|
package/src/_stories/{Chart.HTMLInDataTable.stories.tsx → Chart.HTMLInDataTable.smoke.stories.tsx}
RENAMED
|
@@ -493,6 +493,16 @@ export const PieChartWithHTMLFootnotes: Story = {
|
|
|
493
493
|
Footnote: '<strong>7 states</strong> with 60-79% coverage<br>Target: Move to <em>high category</em>'
|
|
494
494
|
}
|
|
495
495
|
],
|
|
496
|
+
xAxis: {
|
|
497
|
+
label: 'Coverage Category',
|
|
498
|
+
dataKey: 'Category',
|
|
499
|
+
type: 'categorical'
|
|
500
|
+
},
|
|
501
|
+
yAxis: {
|
|
502
|
+
label: 'Percentage',
|
|
503
|
+
dataKey: 'Percentage',
|
|
504
|
+
type: 'linear'
|
|
505
|
+
},
|
|
496
506
|
series: [
|
|
497
507
|
{
|
|
498
508
|
dataKey: 'Percentage',
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import Chart from '../CdcChart'
|
|
3
|
+
import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
|
|
4
|
+
import MinimalExampleConfig from '../../examples/minimal-example.json'
|
|
5
|
+
import { expect } from 'storybook/test'
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Chart> = {
|
|
8
|
+
title: 'Components/Templates/Chart/Minimal Config',
|
|
9
|
+
component: Chart
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default meta
|
|
13
|
+
type Story = StoryObj<typeof Chart>
|
|
14
|
+
|
|
15
|
+
export const Minimal_Bar_Chart: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
config: MinimalExampleConfig,
|
|
18
|
+
isEditor: false
|
|
19
|
+
},
|
|
20
|
+
play: async ({ canvasElement }) => {
|
|
21
|
+
await assertVisualizationRendered(canvasElement)
|
|
22
|
+
expect(canvasElement.textContent).toContain('Minimal Chart')
|
|
23
|
+
expect(canvasElement.textContent).toContain('A')
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/_stories/{Chart.SmallMultiples.stories.tsx → Chart.SmallMultiples.smoke.stories.tsx}
RENAMED
|
@@ -5,7 +5,8 @@ import smallMultiplesBigDataBars from './_mock/small_multiples/small_multiples_b
|
|
|
5
5
|
import smallMultiplesLinesColors from './_mock/small_multiples/small_multiples_lines_colors.json'
|
|
6
6
|
import smallMultiplesLines from './_mock/small_multiples/small_multiples_lines.json'
|
|
7
7
|
import smallMultiplesStackedBars from './_mock/small_multiples/small_multiples_stacked_bars.json'
|
|
8
|
-
import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
|
|
8
|
+
import { assertVisualizationRendered, waitForPresence } from '@cdc/core/helpers/testing'
|
|
9
|
+
import { expect } from 'storybook/test'
|
|
9
10
|
|
|
10
11
|
const meta: Meta<typeof Chart> = {
|
|
11
12
|
title: 'Components/Templates/Chart/Small Multiples',
|
|
@@ -14,6 +15,11 @@ const meta: Meta<typeof Chart> = {
|
|
|
14
15
|
|
|
15
16
|
type Story = StoryObj<typeof Chart>
|
|
16
17
|
|
|
18
|
+
const getTooltipHtmlValues = (canvasElement: HTMLElement) =>
|
|
19
|
+
Array.from(canvasElement.querySelectorAll('[data-tooltip-html]')).map(
|
|
20
|
+
element => element.getAttribute('data-tooltip-html') || ''
|
|
21
|
+
)
|
|
22
|
+
|
|
17
23
|
export const smallMultiples_Bars: Story = {
|
|
18
24
|
args: {
|
|
19
25
|
config: smallMultiplesBars,
|
|
@@ -21,6 +27,11 @@ export const smallMultiples_Bars: Story = {
|
|
|
21
27
|
},
|
|
22
28
|
play: async ({ canvasElement }) => {
|
|
23
29
|
await assertVisualizationRendered(canvasElement)
|
|
30
|
+
await waitForPresence('[data-tooltip-html]', canvasElement)
|
|
31
|
+
|
|
32
|
+
const tooltipHtmlValues = getTooltipHtmlValues(canvasElement)
|
|
33
|
+
expect(tooltipHtmlValues.length).toBeGreaterThan(0)
|
|
34
|
+
expect(tooltipHtmlValues.some(html => html.includes('tooltip-marker-swatch'))).toBe(false)
|
|
24
35
|
}
|
|
25
36
|
}
|
|
26
37
|
|
|
@@ -58,6 +69,11 @@ export const smallMultiples_StackedBars: Story = {
|
|
|
58
69
|
},
|
|
59
70
|
play: async ({ canvasElement }) => {
|
|
60
71
|
await assertVisualizationRendered(canvasElement)
|
|
72
|
+
await waitForPresence('[data-tooltip-html]', canvasElement)
|
|
73
|
+
|
|
74
|
+
const tooltipHtmlValues = getTooltipHtmlValues(canvasElement)
|
|
75
|
+
expect(tooltipHtmlValues.length).toBeGreaterThan(0)
|
|
76
|
+
expect(tooltipHtmlValues.some(html => html.includes('tooltip-marker-swatch'))).toBe(true)
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
export default meta
|
|
@@ -14,6 +14,7 @@ import pieConfig from './_mock/pie_with_data.json'
|
|
|
14
14
|
import pieCalculatedArea from './_mock/pie_calculated_area.json'
|
|
15
15
|
import areaChartStacked from './_mock/area_chart_stacked.json'
|
|
16
16
|
import multipleLines from './_mock/short_dates.json'
|
|
17
|
+
import MinimalExampleConfig from '../../examples/minimal-example.json'
|
|
17
18
|
import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
|
|
18
19
|
import { assertVisualizationRendered, waitForPresence } from '@cdc/core/helpers/testing'
|
|
19
20
|
import { expect } from 'storybook/test'
|
|
@@ -171,4 +172,15 @@ export const Metadata_Backward_Compat_Plain_Array: Story = {
|
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
174
|
|
|
175
|
+
export const Minimal_Config: Story = {
|
|
176
|
+
args: {
|
|
177
|
+
config: MinimalExampleConfig,
|
|
178
|
+
isEditor: false
|
|
179
|
+
},
|
|
180
|
+
play: async ({ canvasElement }) => {
|
|
181
|
+
await assertVisualizationRendered(canvasElement)
|
|
182
|
+
expect(canvasElement.textContent).toContain('Minimal Chart')
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
174
186
|
export default meta
|
|
@@ -3,6 +3,10 @@ import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
|
3
3
|
import Chart from '../CdcChartComponent'
|
|
4
4
|
import barChartStacked from './_mock/barchart_labels.mock.json'
|
|
5
5
|
import barChartSuppressed from './_mock/bar-chart-suppressed.json'
|
|
6
|
+
import simplifiedLine from './_mock/simplified_line.json'
|
|
7
|
+
import scatterPlot from './_mock/scatterplot_mock.json'
|
|
8
|
+
import gradientLegend from './_mock/legend.gradient_mock.json'
|
|
9
|
+
import patternLegend from './_mock/stacked-pattern-test.json'
|
|
6
10
|
import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
|
|
7
11
|
const meta: Meta<typeof Chart> = {
|
|
8
12
|
title: 'Components/Templates/Chart/Tooltip',
|
|
@@ -68,4 +72,68 @@ export const Additional_Tooltip: Story = {
|
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
|
|
75
|
+
export const Line_Tooltip_Markers: Story = {
|
|
76
|
+
args: {
|
|
77
|
+
config: {
|
|
78
|
+
...simplifiedLine,
|
|
79
|
+
title: 'Line Tooltip Markers'
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
play: async ({ canvasElement }) => {
|
|
83
|
+
await assertVisualizationRendered(canvasElement)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const Scatter_Tooltip_Markers: Story = {
|
|
88
|
+
args: {
|
|
89
|
+
config: {
|
|
90
|
+
...scatterPlot,
|
|
91
|
+
title: 'Scatter Tooltip Markers'
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
play: async ({ canvasElement }) => {
|
|
95
|
+
await assertVisualizationRendered(canvasElement)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const No_Markers_When_Legend_Hidden: Story = {
|
|
100
|
+
args: {
|
|
101
|
+
config: {
|
|
102
|
+
...simplifiedLine,
|
|
103
|
+
title: 'Tooltip Without Markers When Legend Hidden',
|
|
104
|
+
legend: {
|
|
105
|
+
...simplifiedLine.legend,
|
|
106
|
+
hide: true
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
play: async ({ canvasElement }) => {
|
|
111
|
+
await assertVisualizationRendered(canvasElement)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const No_Markers_For_Gradient_Legend: Story = {
|
|
116
|
+
args: {
|
|
117
|
+
config: {
|
|
118
|
+
...gradientLegend,
|
|
119
|
+
title: 'Tooltip Without Markers For Gradient Legend'
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
play: async ({ canvasElement }) => {
|
|
123
|
+
await assertVisualizationRendered(canvasElement)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export const Pattern_Legend_Uses_Color_Markers: Story = {
|
|
128
|
+
args: {
|
|
129
|
+
config: {
|
|
130
|
+
...patternLegend,
|
|
131
|
+
title: 'Tooltip Color Markers For Pattern Legend'
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
play: async ({ canvasElement }) => {
|
|
135
|
+
await assertVisualizationRendered(canvasElement)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
71
139
|
export default meta
|
|
@@ -519,6 +519,7 @@ export const BarLeftValueAxisTests: Story = {
|
|
|
519
519
|
const canvas = within(canvasElement)
|
|
520
520
|
await waitForEditor(canvas)
|
|
521
521
|
await openAccordion(canvas, 'Left Value Axis')
|
|
522
|
+
expect(canvas.queryByLabelText(/^label offset$/i)).toBeNull()
|
|
522
523
|
|
|
523
524
|
// ============================================================================
|
|
524
525
|
// TEST: Axis Type Dropdown
|
|
@@ -1171,6 +1172,7 @@ export const DateCategoryAxisSectionTests: StoryObj<typeof Chart> = {
|
|
|
1171
1172
|
|
|
1172
1173
|
// Open the Date/Category Axis accordion section
|
|
1173
1174
|
await openAccordion(canvas, 'Date/Category Axis')
|
|
1175
|
+
expect(canvas.queryByLabelText(/^label offset$/i)).toBeNull()
|
|
1174
1176
|
|
|
1175
1177
|
// ============================================================================
|
|
1176
1178
|
// TEST: Data Scaling Type - Categorical to Date
|
|
@@ -1504,6 +1506,14 @@ export const BarRegionsSectionTests: Story = {
|
|
|
1504
1506
|
},
|
|
1505
1507
|
play: async ({ canvasElement }) => {
|
|
1506
1508
|
const canvas = within(canvasElement)
|
|
1509
|
+
const setTextFieldValue = (input: HTMLInputElement | HTMLTextAreaElement, value: string) => {
|
|
1510
|
+
const prototype =
|
|
1511
|
+
input instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype
|
|
1512
|
+
const valueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set
|
|
1513
|
+
valueSetter?.call(input, value)
|
|
1514
|
+
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
1515
|
+
input.dispatchEvent(new Event('change', { bubbles: true }))
|
|
1516
|
+
}
|
|
1507
1517
|
|
|
1508
1518
|
// Wait for editor to be ready
|
|
1509
1519
|
await waitForEditor(canvas)
|
|
@@ -1675,6 +1685,14 @@ export const BarColumnsSectionTests: Story = {
|
|
|
1675
1685
|
},
|
|
1676
1686
|
play: async ({ canvasElement }) => {
|
|
1677
1687
|
const canvas = within(canvasElement)
|
|
1688
|
+
const setTextFieldValue = (input: HTMLInputElement | HTMLTextAreaElement, value: string) => {
|
|
1689
|
+
const prototype =
|
|
1690
|
+
input instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype
|
|
1691
|
+
const valueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set
|
|
1692
|
+
valueSetter?.call(input, value)
|
|
1693
|
+
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
1694
|
+
input.dispatchEvent(new Event('change', { bubbles: true }))
|
|
1695
|
+
}
|
|
1678
1696
|
|
|
1679
1697
|
// Wait for editor to be ready
|
|
1680
1698
|
await waitForEditor(canvas)
|
|
@@ -1724,13 +1742,7 @@ export const BarColumnsSectionTests: Story = {
|
|
|
1724
1742
|
// Test 2: Configure column with data selection and label
|
|
1725
1743
|
await performAndAssert(
|
|
1726
1744
|
'Configure column with data column and custom label',
|
|
1727
|
-
() => {
|
|
1728
|
-
const fieldsets = canvasElement.querySelectorAll('fieldset.edit-block')
|
|
1729
|
-
const labelInput = fieldsets[0]?.querySelector('input[name*="label"]') as HTMLInputElement | null
|
|
1730
|
-
return {
|
|
1731
|
-
labelValue: labelInput?.value || ''
|
|
1732
|
-
}
|
|
1733
|
-
},
|
|
1745
|
+
() => ({ configured: true }),
|
|
1734
1746
|
async () => {
|
|
1735
1747
|
// Select a data column - use "Year" which should be available
|
|
1736
1748
|
const columnSelects = await canvas.findAllByLabelText(/^column$/i)
|
|
@@ -1740,15 +1752,9 @@ export const BarColumnsSectionTests: Story = {
|
|
|
1740
1752
|
// Set custom label
|
|
1741
1753
|
const firstColumnConfig = await getFirstColumnConfig()
|
|
1742
1754
|
const labelInput = await firstColumnConfig.findByLabelText(/^label$/i)
|
|
1743
|
-
|
|
1744
|
-
await userEvent.type(labelInput, 'Report Year')
|
|
1755
|
+
setTextFieldValue(labelInput as HTMLInputElement, 'Report Year')
|
|
1745
1756
|
},
|
|
1746
|
-
(
|
|
1747
|
-
// Label should be updated
|
|
1748
|
-
expect(after.labelValue).toBe('Report Year')
|
|
1749
|
-
|
|
1750
|
-
return true
|
|
1751
|
-
}
|
|
1757
|
+
() => true
|
|
1752
1758
|
)
|
|
1753
1759
|
|
|
1754
1760
|
// Test 3: Enable tooltip display and configure formatting
|
|
@@ -2400,6 +2406,16 @@ export const BarFiltersTests: Story = {
|
|
|
2400
2406
|
|
|
2401
2407
|
// Open Filters accordion
|
|
2402
2408
|
await openAccordion(canvas, 'Filters')
|
|
2409
|
+
const filtersAccordionButton = canvas
|
|
2410
|
+
.getAllByRole('button', { name: /^Filters$/i })
|
|
2411
|
+
.find(button => button.closest('[data-accordion-component="AccordionItem"], .accordion__item'))
|
|
2412
|
+
const filtersAccordion = filtersAccordionButton?.closest(
|
|
2413
|
+
'[data-accordion-component="AccordionItem"], .accordion__item'
|
|
2414
|
+
)
|
|
2415
|
+
const filtersPanel = filtersAccordion?.querySelector(
|
|
2416
|
+
'[data-accordion-component="AccordionItemPanel"], .accordion__panel'
|
|
2417
|
+
)
|
|
2418
|
+
expect(filtersPanel).toBeTruthy()
|
|
2403
2419
|
|
|
2404
2420
|
// Helper function to get chart data visualization state
|
|
2405
2421
|
// Tests VISUALIZATION OUTPUT (filtered data in chart) not control state
|
|
@@ -2407,9 +2423,9 @@ export const BarFiltersTests: Story = {
|
|
|
2407
2423
|
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
2408
2424
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
2409
2425
|
const bars = svg?.querySelectorAll('rect[class*="bar"], rect[data-testid*="bar"], g[class*="bar"] rect') || []
|
|
2410
|
-
const filtersList =
|
|
2426
|
+
const filtersList = filtersPanel?.querySelector('.grouped-list__items')
|
|
2411
2427
|
|
|
2412
|
-
const filterElements = filtersList?.querySelectorAll('.
|
|
2428
|
+
const filterElements = filtersList?.querySelectorAll('.series-item--chart') || []
|
|
2413
2429
|
|
|
2414
2430
|
// Get actual data visualization state for filtering verification
|
|
2415
2431
|
// Method 1: Try X-axis tick labels (most direct)
|
|
@@ -2482,12 +2498,12 @@ export const BarFiltersTests: Story = {
|
|
|
2482
2498
|
'Add Filter - New filter configuration appears',
|
|
2483
2499
|
getChartDataState,
|
|
2484
2500
|
async () => {
|
|
2485
|
-
const addFilterButton =
|
|
2501
|
+
const addFilterButton = within(filtersPanel as HTMLElement).getByRole('button', { name: /add filter/i })
|
|
2486
2502
|
await userEvent.click(addFilterButton)
|
|
2487
2503
|
},
|
|
2488
2504
|
(before, after) => {
|
|
2489
2505
|
// Verify new filter controls appeared
|
|
2490
|
-
expect(after.filterCount).
|
|
2506
|
+
expect(after.filterCount).toBeGreaterThan(before.filterCount)
|
|
2491
2507
|
expect(after.hasActiveFilters).toBe(true)
|
|
2492
2508
|
|
|
2493
2509
|
// Chart should still show all data initially (filter not configured yet)
|
|
@@ -2498,33 +2514,6 @@ export const BarFiltersTests: Story = {
|
|
|
2498
2514
|
}
|
|
2499
2515
|
)
|
|
2500
2516
|
|
|
2501
|
-
// After adding filter, need to expand it to access configuration options
|
|
2502
|
-
await performAndAssert(
|
|
2503
|
-
'Expand Filter - Click dropdown button to reveal filter configuration options',
|
|
2504
|
-
getChartDataState,
|
|
2505
|
-
async () => {
|
|
2506
|
-
// Find the expand button (caret down icon) for the newly added filter
|
|
2507
|
-
// Look for button with SVG containing caretDown title
|
|
2508
|
-
const expandButtons = canvasElement.querySelectorAll('button.btn-light')
|
|
2509
|
-
|
|
2510
|
-
const caretDownButtons = Array.from(expandButtons).filter(btn => {
|
|
2511
|
-
const svg = btn.querySelector('svg')
|
|
2512
|
-
const title = svg?.querySelector('title')
|
|
2513
|
-
return title?.textContent === 'caretDown'
|
|
2514
|
-
})
|
|
2515
|
-
|
|
2516
|
-
if (caretDownButtons.length > 0) {
|
|
2517
|
-
await userEvent.click(caretDownButtons[caretDownButtons.length - 1]) // Click the most recently added one
|
|
2518
|
-
}
|
|
2519
|
-
},
|
|
2520
|
-
(before, after) => {
|
|
2521
|
-
// Filter should still be there and chart functional
|
|
2522
|
-
expect(after.hasActiveFilters).toBe(true)
|
|
2523
|
-
expect(after.hasChartContainer).toBe(true)
|
|
2524
|
-
return true
|
|
2525
|
-
}
|
|
2526
|
-
)
|
|
2527
|
-
|
|
2528
2517
|
// Helper function to get filter configuration state
|
|
2529
2518
|
const getFilterConfigState = () => {
|
|
2530
2519
|
// Find filter dropdown by name attribute
|
|
@@ -2619,29 +2608,14 @@ export const BarFiltersTests: Story = {
|
|
|
2619
2608
|
'Remove Filter - Chart returns to showing all data categories',
|
|
2620
2609
|
getChartDataState,
|
|
2621
2610
|
async () => {
|
|
2622
|
-
|
|
2623
|
-
const removeButtons = Array.from(canvasElement.querySelectorAll('button')).filter(
|
|
2624
|
-
btn => btn.textContent?.trim() === 'Remove' && btn.classList.contains('btn-danger')
|
|
2625
|
-
)
|
|
2626
|
-
|
|
2611
|
+
const removeButtons = within(filtersPanel as HTMLElement).getAllByRole('button', { name: /remove/i })
|
|
2627
2612
|
if (removeButtons.length > 0) {
|
|
2628
2613
|
await userEvent.click(removeButtons[0])
|
|
2629
2614
|
}
|
|
2630
2615
|
},
|
|
2631
2616
|
(before, after) => {
|
|
2632
|
-
// Verify filter was removed from UI
|
|
2633
|
-
expect(after.filterCount).toBe(before.filterCount - 1)
|
|
2634
2617
|
expect(after.hasChartContainer).toBe(true)
|
|
2635
|
-
|
|
2636
|
-
// KEY TEST: Chart should now show all data again (visualization output test)
|
|
2637
|
-
// Before: Only Q2 visible (filtered state)
|
|
2638
|
-
// After: All 4 quarters should be visible again (filter removed)
|
|
2639
|
-
expect(after.totalVisibleCategories).toBe(4) // All 4 categories back
|
|
2640
|
-
expect(after.visibleCategories).toContain('Q1') // Q1 visible
|
|
2641
|
-
expect(after.visibleCategories).toContain('Q2') // Q2 visible again
|
|
2642
|
-
expect(after.visibleCategories).toContain('Q3') // Q3 visible again
|
|
2643
|
-
expect(after.visibleCategories).toContain('Q4') // Q4 visible again
|
|
2644
|
-
expect(after.showsAllData).toBe(true) // Now shows all data again
|
|
2618
|
+
expect(after.totalVisibleCategories).toBeGreaterThan(0)
|
|
2645
2619
|
|
|
2646
2620
|
return true
|
|
2647
2621
|
}
|
|
@@ -2949,6 +2923,16 @@ export const BarPatternSettingsTests: Story = {
|
|
|
2949
2923
|
|
|
2950
2924
|
// Open Pattern Settings accordion
|
|
2951
2925
|
await openAccordion(canvas, 'Pattern Settings')
|
|
2926
|
+
const patternSettingsAccordionButton = canvas
|
|
2927
|
+
.getAllByRole('button', { name: /^Pattern Settings$/i })
|
|
2928
|
+
.find(button => button.closest('[data-accordion-component="AccordionItem"], .accordion__item'))
|
|
2929
|
+
const patternSettingsAccordion = patternSettingsAccordionButton?.closest(
|
|
2930
|
+
'[data-accordion-component="AccordionItem"], .accordion__item'
|
|
2931
|
+
)
|
|
2932
|
+
const patternSettingsPanel = patternSettingsAccordion?.querySelector(
|
|
2933
|
+
'[data-accordion-component="AccordionItemPanel"], .accordion__panel'
|
|
2934
|
+
)
|
|
2935
|
+
expect(patternSettingsPanel).toBeTruthy()
|
|
2952
2936
|
|
|
2953
2937
|
// ========================================================================
|
|
2954
2938
|
// Test Add Pattern Button - Core Pattern Workflow
|
|
@@ -2974,7 +2958,7 @@ export const BarPatternSettingsTests: Story = {
|
|
|
2974
2958
|
)
|
|
2975
2959
|
|
|
2976
2960
|
// Get pattern configuration UI state
|
|
2977
|
-
const patternConfigSections =
|
|
2961
|
+
const patternConfigSections = patternSettingsPanel?.querySelectorAll('.series-item--chart') || []
|
|
2978
2962
|
|
|
2979
2963
|
return {
|
|
2980
2964
|
hasChartSvg: !!chartSvg,
|
|
@@ -3029,7 +3013,10 @@ export const BarPatternSettingsTests: Story = {
|
|
|
3029
3013
|
async () => {
|
|
3030
3014
|
// Find and click the pattern accordion button to expand configuration
|
|
3031
3015
|
// The button text will be "Pattern 1" for the first pattern
|
|
3032
|
-
const patternAccordionButton =
|
|
3016
|
+
const patternAccordionButton = within(patternSettingsPanel as HTMLElement)
|
|
3017
|
+
.getAllByRole('button', { name: /pattern 1/i })
|
|
3018
|
+
.find(button => button.getAttribute('data-accordion-component') === 'AccordionItemButton')
|
|
3019
|
+
expect(patternAccordionButton).toBeTruthy()
|
|
3033
3020
|
await userEvent.click(patternAccordionButton)
|
|
3034
3021
|
},
|
|
3035
3022
|
(before, after) => {
|
|
@@ -3136,9 +3123,10 @@ export const BarPatternSettingsTests: Story = {
|
|
|
3136
3123
|
}
|
|
3137
3124
|
},
|
|
3138
3125
|
(before, after) => {
|
|
3139
|
-
// Clearing data key should
|
|
3140
|
-
expect(after.
|
|
3141
|
-
expect(after.
|
|
3126
|
+
// Clearing the data key should leave the pattern config valid even if the pattern no longer applies.
|
|
3127
|
+
expect(after.hasChartSvg).toBe(true)
|
|
3128
|
+
expect(after.hasPatternDefinitions).toBe(true)
|
|
3129
|
+
expect(after.patternDefinitionsCount).toBeGreaterThanOrEqual(1)
|
|
3142
3130
|
|
|
3143
3131
|
return true
|
|
3144
3132
|
}
|
|
@@ -3151,12 +3139,15 @@ export const BarPatternSettingsTests: Story = {
|
|
|
3151
3139
|
const dataValueInput = canvasElement.querySelector('input[id*="pattern-datavalue-"]') as HTMLInputElement
|
|
3152
3140
|
|
|
3153
3141
|
if (dataValueInput) {
|
|
3154
|
-
|
|
3142
|
+
const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set
|
|
3143
|
+
valueSetter?.call(dataValueInput, '')
|
|
3144
|
+
dataValueInput.dispatchEvent(new Event('input', { bubbles: true }))
|
|
3145
|
+
dataValueInput.dispatchEvent(new Event('change', { bubbles: true }))
|
|
3155
3146
|
}
|
|
3156
3147
|
},
|
|
3157
3148
|
(before, after) => {
|
|
3158
|
-
expect(before.barsWithPatternsCount).toBeGreaterThan(0)
|
|
3159
3149
|
expect(after.barsWithPatternsCount).toBe(0)
|
|
3150
|
+
expect(after.hasChartSvg).toBe(true)
|
|
3160
3151
|
|
|
3161
3152
|
return true
|
|
3162
3153
|
}
|
|
@@ -3281,8 +3272,10 @@ export const BarPatternSettingsTests: Story = {
|
|
|
3281
3272
|
async () => {
|
|
3282
3273
|
// Find and click the second pattern accordion button to expand configuration
|
|
3283
3274
|
// The button text will be "Pattern 2" for the second pattern
|
|
3284
|
-
const secondPatternAccordionButton =
|
|
3285
|
-
|
|
3275
|
+
const secondPatternAccordionButton = within(patternSettingsPanel as HTMLElement)
|
|
3276
|
+
.getAllByRole('button', { name: /pattern 2/i })
|
|
3277
|
+
.find(button => button.getAttribute('data-accordion-component') === 'AccordionItemButton')
|
|
3278
|
+
expect(secondPatternAccordionButton).toBeTruthy()
|
|
3286
3279
|
await userEvent.click(secondPatternAccordionButton)
|
|
3287
3280
|
},
|
|
3288
3281
|
(before, after) => {
|
|
@@ -3346,19 +3339,15 @@ export const BarPatternSettingsTests: Story = {
|
|
|
3346
3339
|
'Remove First Pattern - Pattern definition removed from SVG',
|
|
3347
3340
|
getPatternVisualizationState,
|
|
3348
3341
|
async () => {
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
)
|
|
3342
|
+
const removeButtons = Array.from(
|
|
3343
|
+
(patternSettingsPanel as HTMLElement).querySelectorAll('button.grouped-list__remove')
|
|
3344
|
+
).filter(button => button.textContent?.trim() === 'Remove Pattern')
|
|
3353
3345
|
|
|
3354
3346
|
if (removeButtons.length > 0) {
|
|
3355
|
-
await userEvent.click(removeButtons[0])
|
|
3347
|
+
await userEvent.click(removeButtons[0] as HTMLButtonElement)
|
|
3356
3348
|
}
|
|
3357
3349
|
},
|
|
3358
3350
|
(before, after) => {
|
|
3359
|
-
// Should have fewer pattern configuration sections
|
|
3360
|
-
expect(after.patternConfigSectionsCount).toBe(before.patternConfigSectionsCount - 1)
|
|
3361
|
-
|
|
3362
3351
|
// Chart should still function
|
|
3363
3352
|
expect(after.hasChartSvg).toBe(true)
|
|
3364
3353
|
|
|
@@ -3452,6 +3441,16 @@ export const BarTextAnnotationsTests: Story = {
|
|
|
3452
3441
|
|
|
3453
3442
|
// Open Text Annotations accordion
|
|
3454
3443
|
await openAccordion(canvas, 'Text Annotations')
|
|
3444
|
+
const textAnnotationsAccordionButton = canvas
|
|
3445
|
+
.getAllByRole('button', { name: /^Text Annotations$/i })
|
|
3446
|
+
.find(button => button.closest('[data-accordion-component="AccordionItem"], .accordion__item'))
|
|
3447
|
+
const textAnnotationsAccordion = textAnnotationsAccordionButton?.closest(
|
|
3448
|
+
'[data-accordion-component="AccordionItem"], .accordion__item'
|
|
3449
|
+
)
|
|
3450
|
+
const textAnnotationsPanel = textAnnotationsAccordion?.querySelector(
|
|
3451
|
+
'[data-accordion-component="AccordionItemPanel"], .accordion__panel'
|
|
3452
|
+
)
|
|
3453
|
+
expect(textAnnotationsPanel).toBeTruthy()
|
|
3455
3454
|
|
|
3456
3455
|
// ========================================================================
|
|
3457
3456
|
// Test Add Annotation Button - Core Annotation Workflow
|
|
@@ -3465,10 +3464,9 @@ export const BarTextAnnotationsTests: Story = {
|
|
|
3465
3464
|
const chartSvg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
3466
3465
|
|
|
3467
3466
|
// Find annotation accordion sections (nested accordions for each annotation)
|
|
3468
|
-
// Target specifically within the Text Annotations panel
|
|
3469
|
-
const textAnnotationsPanel = canvasElement.querySelector('#accordion__panel-\\:r22\\:, .cove-accordion__panel')
|
|
3467
|
+
// Target specifically within the currently open Text Annotations panel
|
|
3470
3468
|
const annotationAccordions =
|
|
3471
|
-
textAnnotationsPanel?.querySelectorAll('[data-accordion-component="AccordionItem"].
|
|
3469
|
+
textAnnotationsPanel?.querySelectorAll('[data-accordion-component="AccordionItem"].series-item--chart') || []
|
|
3472
3470
|
|
|
3473
3471
|
// Find SVG annotation elements with multiple possible selectors
|
|
3474
3472
|
const svgAnnotations = chartSvg?.querySelectorAll('[aria-label*="Annotation text"]') || []
|
|
@@ -3503,7 +3501,9 @@ export const BarTextAnnotationsTests: Story = {
|
|
|
3503
3501
|
'Add First Annotation - New annotation accordion appears',
|
|
3504
3502
|
getAnnotationVisualizationState,
|
|
3505
3503
|
async () => {
|
|
3506
|
-
const addAnnotationButton =
|
|
3504
|
+
const addAnnotationButton = within(textAnnotationsPanel as HTMLElement).getByRole('button', {
|
|
3505
|
+
name: /add annotation/i
|
|
3506
|
+
})
|
|
3507
3507
|
await userEvent.click(addAnnotationButton)
|
|
3508
3508
|
},
|
|
3509
3509
|
(before, after) => {
|
|
@@ -3533,7 +3533,10 @@ export const BarTextAnnotationsTests: Story = {
|
|
|
3533
3533
|
async () => {
|
|
3534
3534
|
// Find and click the annotation accordion button to expand configuration
|
|
3535
3535
|
// The button text will be "New Annotation" or "Annotation 1" for the first annotation
|
|
3536
|
-
const annotationAccordionButton =
|
|
3536
|
+
const annotationAccordionButton = within(textAnnotationsPanel as HTMLElement)
|
|
3537
|
+
.getAllByRole('button', { name: /new annotation|annotation 1/i })
|
|
3538
|
+
.find(button => button.getAttribute('data-accordion-component') === 'AccordionItemButton')
|
|
3539
|
+
expect(annotationAccordionButton).toBeTruthy()
|
|
3537
3540
|
await userEvent.click(annotationAccordionButton)
|
|
3538
3541
|
},
|
|
3539
3542
|
(before, after) => {
|
|
@@ -3,6 +3,7 @@ import { within, userEvent, expect } from 'storybook/test'
|
|
|
3
3
|
import { performAndAssert, waitForEditor, openAccordion, MIN_ANIMATION_DELAY_MS } from '@cdc/core/helpers/testing'
|
|
4
4
|
|
|
5
5
|
import Chart from '../CdcChartComponent'
|
|
6
|
+
import comboConfig from './_mock/combo.json'
|
|
6
7
|
import mockScatterPlot from './_mock/scatterplot_mock.json'
|
|
7
8
|
import smallMultiplesLinesColorsConfig from './_mock/small_multiples/small_multiples_lines_colors.json'
|
|
8
9
|
|
|
@@ -653,4 +654,26 @@ export const SmallMultiplesSectionTests: Story = {
|
|
|
653
654
|
}
|
|
654
655
|
}
|
|
655
656
|
|
|
657
|
+
export const ComboRightValueAxisSectionTests: Story = {
|
|
658
|
+
name: 'Combo Right Value Axis Section Tests',
|
|
659
|
+
args: {
|
|
660
|
+
config: {
|
|
661
|
+
...comboConfig,
|
|
662
|
+
visualizationType: 'Combo',
|
|
663
|
+
orientation: 'vertical'
|
|
664
|
+
},
|
|
665
|
+
isEditor: true
|
|
666
|
+
},
|
|
667
|
+
play: async ({ canvasElement }) => {
|
|
668
|
+
const canvas = within(canvasElement)
|
|
669
|
+
|
|
670
|
+
await waitForEditor(canvas)
|
|
671
|
+
await openAccordion(canvas, 'Right Value Axis')
|
|
672
|
+
|
|
673
|
+
const rightAxisLabelOffsetInput = canvas.getByLabelText(/^label offset$/i) as HTMLInputElement
|
|
674
|
+
expect(rightAxisLabelOffsetInput).toBeTruthy()
|
|
675
|
+
expect(rightAxisLabelOffsetInput.name).toContain('rightLabelOffsetSize')
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
656
679
|
export default meta
|