@cdc/chart 4.26.1 → 4.26.3
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/CLAUDE.local.md +79 -0
- package/LICENSE +201 -0
- package/dist/{cdcchart-dgT_1dIT.es.js → cdcchart-DQ00cQCm.es.js} +1 -20
- package/dist/cdcchart.js +54742 -49796
- package/examples/data/data-with-metadata.json +10 -0
- package/examples/default.json +378 -0
- package/examples/feature/__data__/horizon-chart-data.json +373 -0
- package/examples/feature/annotations/index.json +3 -6
- package/examples/feature/horizon/horizon-chart.json +395 -0
- package/examples/feature/pie/planet-pie-example-config.json +2 -1
- package/examples/line-chart-states.json +1085 -0
- package/examples/metadata-variables.json +58 -0
- package/examples/private/123.json +694 -0
- package/examples/private/anchor-issue.json +4094 -0
- package/examples/private/backwards-slider.json +10430 -0
- package/examples/private/georgia.csv +160 -0
- package/examples/private/timeline-data.json +1 -0
- package/examples/private/timeline.json +389 -0
- package/examples/radar-chart-simple.json +133 -0
- package/examples/radar-chart.json +148 -0
- package/index.html +1 -31
- package/package.json +57 -59
- package/src/CdcChart.tsx +8 -4
- package/src/CdcChartComponent.tsx +398 -284
- package/src/_stories/Chart.Anchors.stories.tsx +10 -0
- package/src/_stories/Chart.BoxPlot.stories.tsx +7 -0
- package/src/_stories/Chart.CI.stories.tsx +13 -0
- package/src/_stories/Chart.Combo.stories.tsx +17 -0
- package/src/_stories/Chart.CustomColors.stories.tsx +78 -0
- package/src/_stories/Chart.Defaults.stories.tsx +95 -0
- package/src/_stories/Chart.DynamicSeries.stories.tsx +19 -0
- package/src/_stories/Chart.Filters.stories.tsx +4 -0
- package/src/_stories/Chart.Forecast.stories.tsx +4 -0
- package/src/_stories/Chart.HTMLInDataTable.stories.tsx +22 -0
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +28 -0
- package/src/_stories/Chart.Patterns.stories.tsx +4 -0
- package/src/_stories/Chart.PreserveDecimals.stories.tsx +25 -0
- package/src/_stories/Chart.Regions.Categorical.stories.tsx +13 -0
- package/src/_stories/Chart.Regions.DateScale.stories.tsx +19 -0
- package/src/_stories/Chart.Regions.DateTimeScale.stories.tsx +25 -10
- package/src/_stories/Chart.ScatterPlot.stories.tsx +4 -0
- package/src/_stories/Chart.SmallMultiples.stories.tsx +16 -0
- package/src/_stories/Chart.SmallestLeftAxisMax.stories.tsx +64 -0
- package/src/_stories/Chart.stories.tsx +72 -1
- package/src/_stories/Chart.tooltip.stories.tsx +7 -0
- package/src/_stories/ChartAnnotation.stories.tsx +10 -0
- package/src/_stories/ChartAxisLabels.stories.tsx +4 -0
- package/src/_stories/ChartAxisTitles.stories.tsx +10 -0
- package/src/_stories/ChartBar.Editor.stories.tsx +97 -38
- package/src/_stories/ChartBrush.Editor.stories.tsx +11 -25
- package/src/_stories/ChartBrush.Matrix.Continuous.stories.tsx +41 -0
- package/src/_stories/ChartBrush.Matrix.Date.stories.tsx +114 -0
- package/src/_stories/ChartBrush.Matrix.DateTime.stories.tsx +78 -0
- package/src/_stories/ChartBrush.stories.tsx +7 -0
- package/src/_stories/ChartEditor.Editor.stories.tsx +1 -1
- package/src/_stories/ChartEditor.stories.tsx +7 -0
- package/src/_stories/ChartLine.QuadrantAngles.stories.tsx +89 -0
- package/src/_stories/ChartLine.Suppression.stories.tsx +7 -0
- package/src/_stories/ChartLine.Symbols.stories.tsx +4 -0
- package/src/_stories/ChartPrefixSuffix.stories.tsx +46 -1
- package/src/_stories/TechAdoptionWithLinks.stories.tsx +7 -0
- package/src/_stories/_mock/brush_continuous.json +86 -0
- package/src/_stories/_mock/brush_date_large.json +176 -0
- package/src/_stories/_mock/line_chart_angle_near_zero_fall.json +195 -0
- package/src/_stories/_mock/line_chart_angle_near_zero_rise.json +195 -0
- package/src/_stories/_mock/line_chart_angle_q1_steep_upward.json +195 -0
- package/src/_stories/_mock/line_chart_angle_q2_gentle_downward.json +195 -0
- package/src/_stories/_mock/line_chart_angle_q3_steep_downward.json +195 -0
- package/src/_stories/_mock/line_chart_angle_q4_gentle_upward.json +195 -0
- package/src/_stories/_mock/line_chart_quadrant_angles.json +264 -0
- package/src/_stories/_mock/paired-bar-abbr.json +421 -0
- package/src/_stories/_mock/pie_custom_colors.json +268 -0
- package/src/_stories/_mock/smallest_left_axis_max.json +104 -0
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +14 -20
- package/src/components/Annotations/components/AnnotationDraggable.tsx +240 -116
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +1 -2
- package/src/components/Annotations/components/AnnotationDropdown.tsx +8 -12
- package/src/components/Annotations/components/AnnotationList.styles.css +12 -18
- package/src/components/Annotations/components/AnnotationList.tsx +5 -4
- package/src/components/Annotations/components/findNearestDatum.ts +75 -85
- package/src/components/Annotations/helpers/getVisibleAnnotations.ts +38 -0
- package/src/components/Axis/BottomAxis.tsx +277 -0
- package/src/components/Axis/LeftAxis.tsx +404 -0
- package/src/components/Axis/LeftAxisGridlines.tsx +77 -0
- package/src/components/Axis/PairedBarAxis.tsx +192 -0
- package/src/components/Axis/README.md +94 -0
- package/src/components/Axis/RightAxis.tsx +108 -0
- package/src/components/Axis/axis.constants.ts +21 -0
- package/src/components/Axis/index.ts +7 -0
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +12 -28
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +12 -30
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +12 -31
- package/src/components/BarChart/components/BarChart.Vertical.tsx +12 -28
- package/src/components/BarChart/components/BarChart.tsx +7 -1
- package/src/components/BarChart/helpers/getPatternUrl.ts +94 -0
- package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +134 -0
- package/src/components/BarChart/helpers/useBarChart.ts +3 -0
- package/src/components/Brush/BrushSelector.tsx +155 -22
- package/src/components/Brush/MiniChartPreview.tsx +133 -21
- package/src/components/EditorPanel/EditorPanel.tsx +81 -54
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +67 -29
- package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +0 -78
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +120 -2
- package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +25 -43
- package/src/components/EditorPanel/components/Panels/Panel.Radar.tsx +353 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +83 -3
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +66 -43
- package/src/components/EditorPanel/components/Panels/index.tsx +2 -0
- package/src/components/EditorPanel/editor-panel.scss +1 -1
- package/src/components/EditorPanel/useEditorPermissions.ts +55 -26
- package/src/components/ForestPlot/ForestPlot.tsx +26 -22
- package/src/components/HorizonChart/HorizonChart.tsx +131 -0
- package/src/components/HorizonChart/components/HorizonBand.tsx +160 -0
- package/src/components/HorizonChart/helpers/calculateHorizonBands.ts +27 -0
- package/src/components/HorizonChart/helpers/getHorizonLayerColors.ts +40 -0
- package/src/components/HorizonChart/index.tsx +3 -0
- package/src/components/Legend/Legend.Component.tsx +52 -4
- package/src/components/Legend/Legend.tsx +1 -1
- package/src/components/Legend/LegendGroup/LegendGroup.styles.css +4 -4
- package/src/components/Legend/LegendValueRange.tsx +77 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +16 -2
- package/src/components/Legend/helpers/generateValueRanges.ts +92 -0
- package/src/components/LineChart/helpers/README.md +292 -0
- package/src/components/LineChart/helpers/labelPositioning.test.ts +245 -0
- package/src/components/LineChart/helpers/labelPositioning.ts +304 -0
- package/src/components/LineChart/index.tsx +44 -8
- package/src/components/LinearChart/README.md +109 -0
- package/src/components/LinearChart/VisualizationRenderer.tsx +267 -0
- package/src/components/LinearChart/linearChart.constants.ts +84 -0
- package/src/components/LinearChart/tests/LinearChart.test.tsx +278 -0
- package/src/components/LinearChart/tests/mockConfigContext.ts +131 -0
- package/src/components/LinearChart/utils/tickFormatting.ts +146 -0
- package/src/components/LinearChart.tsx +268 -1057
- package/src/components/PieChart/PieChart.tsx +20 -5
- package/src/components/RadarChart/RadarAxis.tsx +78 -0
- package/src/components/RadarChart/RadarChart.tsx +298 -0
- package/src/components/RadarChart/RadarGrid.tsx +64 -0
- package/src/components/RadarChart/RadarPolygon.tsx +91 -0
- package/src/components/RadarChart/helpers.ts +83 -0
- package/src/components/RadarChart/index.tsx +3 -0
- package/src/components/Regions/components/Regions.tsx +6 -6
- package/src/components/Sankey/components/Sankey.tsx +3 -3
- package/src/components/Sankey/sankey.scss +1 -1
- package/src/components/SmallMultiples/SmallMultiples.css +5 -5
- package/src/components/Sparkline/index.scss +4 -2
- package/src/components/WarmingStripes/WarmingStripes.tsx +95 -25
- package/src/components/WarmingStripes/WarmingStripesGradientLegend.css +8 -8
- package/src/data/initial-state.js +37 -15
- package/src/data/legacy-defaults.ts +18 -0
- package/src/helpers/abbreviateNumber.ts +24 -17
- package/src/helpers/getChartPatternId.ts +17 -0
- package/src/helpers/getExcludedData.ts +4 -0
- package/src/helpers/getMinMax.ts +16 -2
- package/src/helpers/handleChartAriaLabels.ts +19 -19
- package/src/helpers/handleLineType.ts +22 -18
- package/src/helpers/seriesColumnSettings.ts +114 -0
- package/src/helpers/tests/countNumOfTicks.test.ts +77 -0
- package/src/helpers/tests/seriesColumnSettings.test.ts +84 -0
- package/src/hooks/useProgrammaticTooltip.ts +23 -2
- package/src/hooks/useRightAxis.ts +14 -0
- package/src/hooks/useScales.ts +99 -56
- package/src/hooks/useTooltip.tsx +23 -3
- package/src/scss/main.scss +157 -79
- package/src/selectors/README.md +68 -0
- package/src/store/chart.reducer.ts +2 -0
- package/src/test/CdcChart.test.jsx +2 -2
- package/src/types/ChartConfig.ts +22 -0
- package/src/types/ChartContext.ts +1 -0
- package/src/types/Horizon.ts +64 -0
- package/tests/fixtures/chart-config-with-metadata.json +29 -0
- package/tests/fixtures/data-with-metadata.json +10 -0
- package/preview.html +0 -1616
- package/src/components/Annotations/components/helpers/index.tsx +0 -46
|
@@ -4,6 +4,7 @@ import longXLabelsConfig from './_mock/large_x_axis_labels.json'
|
|
|
4
4
|
import pairedBarConfig from './_mock/paired-bar.json'
|
|
5
5
|
import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
|
|
6
6
|
import { ChartConfig } from '../types/ChartConfig'
|
|
7
|
+
import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
|
|
7
8
|
|
|
8
9
|
const meta: Meta<typeof Chart> = {
|
|
9
10
|
title: 'Components/Templates/Chart/Axis Titles',
|
|
@@ -17,6 +18,9 @@ type Story = StoryObj<typeof Chart>
|
|
|
17
18
|
export const Dynamic_Labels: Story = {
|
|
18
19
|
args: {
|
|
19
20
|
config: editConfigKeys(longXLabelsConfig, [{ path: ['xAxis', 'label'], value: 'This is the title' }])
|
|
21
|
+
},
|
|
22
|
+
play: async ({ canvasElement }) => {
|
|
23
|
+
await assertVisualizationRendered(canvasElement)
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
|
|
@@ -43,11 +47,17 @@ export const Rotated_Labels: StoryObj<{ config: ChartConfig; tickRotation: numbe
|
|
|
43
47
|
])
|
|
44
48
|
|
|
45
49
|
return <Chart config={config} />
|
|
50
|
+
},
|
|
51
|
+
play: async ({ canvasElement }) => {
|
|
52
|
+
await assertVisualizationRendered(canvasElement)
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
export const Paired_Bar: Story = {
|
|
50
57
|
args: {
|
|
51
58
|
config: pairedBarConfig
|
|
59
|
+
},
|
|
60
|
+
play: async ({ canvasElement }) => {
|
|
61
|
+
await assertVisualizationRendered(canvasElement)
|
|
52
62
|
}
|
|
53
63
|
}
|
|
@@ -92,7 +92,7 @@ export const BarGeneralTests: Story = {
|
|
|
92
92
|
|
|
93
93
|
const getChartSubtypeVisualization = () => {
|
|
94
94
|
// Target the chart visualization SVG specifically, not editor UI icons
|
|
95
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
95
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
96
96
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
97
97
|
const legendContainer = canvasElement.querySelector('.legend, [class*="legend"]')
|
|
98
98
|
|
|
@@ -160,7 +160,7 @@ export const BarGeneralTests: Story = {
|
|
|
160
160
|
|
|
161
161
|
const getOrientationVisualization = () => {
|
|
162
162
|
// Target the chart visualization SVG specifically, not editor UI icons
|
|
163
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
163
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
164
164
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
165
165
|
|
|
166
166
|
// Look for bar elements - different structures for horizontal vs vertical
|
|
@@ -273,7 +273,7 @@ export const BarGeneralTests: Story = {
|
|
|
273
273
|
|
|
274
274
|
const getBarStyleVisualization = () => {
|
|
275
275
|
// Target the chart visualization SVG specifically, not editor UI icons
|
|
276
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
276
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
277
277
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
278
278
|
|
|
279
279
|
return {
|
|
@@ -528,7 +528,7 @@ export const BarLeftValueAxisTests: Story = {
|
|
|
528
528
|
|
|
529
529
|
const getAxisTypeVisualization = () => {
|
|
530
530
|
// Target the chart visualization SVG specifically, not editor UI icons
|
|
531
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
531
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
532
532
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
533
533
|
|
|
534
534
|
// Find the left axis specifically
|
|
@@ -693,7 +693,7 @@ export const BarLeftValueAxisTests: Story = {
|
|
|
693
693
|
|
|
694
694
|
const getAxisLabelVisualization = () => {
|
|
695
695
|
// Target the chart visualization SVG specifically, not editor UI icons
|
|
696
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
696
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
697
697
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
698
698
|
|
|
699
699
|
// Find Y-axis label elements with multiple possible selectors
|
|
@@ -795,7 +795,9 @@ export const BarLeftValueAxisTests: Story = {
|
|
|
795
795
|
expect(yAxisLabelInput.value).toBe('Custom Y-Axis Label')
|
|
796
796
|
|
|
797
797
|
// Debug: Log the label element to confirm selection
|
|
798
|
-
const chartContainer = canvasElement.querySelector(
|
|
798
|
+
const chartContainer = canvasElement.querySelector(
|
|
799
|
+
'.cove-visualization__body, .chart-container, .visualization'
|
|
800
|
+
)
|
|
799
801
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
800
802
|
const labelElement = svg?.querySelector('text.y-label')
|
|
801
803
|
|
|
@@ -853,7 +855,7 @@ export const BarLeftValueAxisTests: Story = {
|
|
|
853
855
|
|
|
854
856
|
const getInlineLabelVisualization = () => {
|
|
855
857
|
// Target the chart visualization SVG specifically, not editor UI icons
|
|
856
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
858
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
857
859
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
858
860
|
|
|
859
861
|
// Find the Y-axis area to locate the top tick area
|
|
@@ -989,7 +991,7 @@ export const BarLeftValueAxisTests: Story = {
|
|
|
989
991
|
|
|
990
992
|
const getNumTicksVisualization = () => {
|
|
991
993
|
// Target the chart visualization SVG specifically, not editor UI icons
|
|
992
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
994
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
993
995
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
994
996
|
|
|
995
997
|
// Find the left axis specifically
|
|
@@ -1190,7 +1192,7 @@ export const DateCategoryAxisSectionTests: StoryObj<typeof Chart> = {
|
|
|
1190
1192
|
// Method 2: Look for SVG in chart container areas
|
|
1191
1193
|
if (!svgElement) {
|
|
1192
1194
|
const chartContainer = canvasElement.querySelector(
|
|
1193
|
-
'.cove-
|
|
1195
|
+
'.cove-visualization__body, .chart-container, .visualization, .linear'
|
|
1194
1196
|
)
|
|
1195
1197
|
if (chartContainer) {
|
|
1196
1198
|
svgElement = chartContainer.querySelector('svg')
|
|
@@ -1541,7 +1543,7 @@ export const BarRegionsSectionTests: Story = {
|
|
|
1541
1543
|
await performAndAssert(
|
|
1542
1544
|
'Configure Fixed-to-Fixed region with label and colors',
|
|
1543
1545
|
() => {
|
|
1544
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
1546
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body')
|
|
1545
1547
|
const chartSvg = chartContainer?.querySelector('svg')
|
|
1546
1548
|
const regionElements = chartSvg?.querySelectorAll('rect[fill*="rgba"], rect[style*="rgba"]') || []
|
|
1547
1549
|
|
|
@@ -1680,6 +1682,17 @@ export const BarColumnsSectionTests: Story = {
|
|
|
1680
1682
|
// Open Columns accordion
|
|
1681
1683
|
await openAccordion(canvas, 'Columns')
|
|
1682
1684
|
|
|
1685
|
+
const getFirstColumnConfig = async () => {
|
|
1686
|
+
const columnSelect = (await canvas.findAllByLabelText(/^column$/i))[0]
|
|
1687
|
+
const fieldset = columnSelect.closest('fieldset')
|
|
1688
|
+
|
|
1689
|
+
if (!fieldset) {
|
|
1690
|
+
throw new Error('Unable to find the first column configuration fieldset')
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
return within(fieldset as HTMLElement)
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1683
1696
|
// Test 1: Add first column configuration and verify fields appear
|
|
1684
1697
|
await performAndAssert(
|
|
1685
1698
|
'Add first column configuration and verify fields appear',
|
|
@@ -1712,9 +1725,10 @@ export const BarColumnsSectionTests: Story = {
|
|
|
1712
1725
|
await performAndAssert(
|
|
1713
1726
|
'Configure column with data column and custom label',
|
|
1714
1727
|
() => {
|
|
1715
|
-
const
|
|
1728
|
+
const fieldsets = canvasElement.querySelectorAll('fieldset.edit-block')
|
|
1729
|
+
const labelInput = fieldsets[0]?.querySelector('input[name*="label"]') as HTMLInputElement | null
|
|
1716
1730
|
return {
|
|
1717
|
-
labelValue:
|
|
1731
|
+
labelValue: labelInput?.value || ''
|
|
1718
1732
|
}
|
|
1719
1733
|
},
|
|
1720
1734
|
async () => {
|
|
@@ -1724,8 +1738,8 @@ export const BarColumnsSectionTests: Story = {
|
|
|
1724
1738
|
await userEvent.selectOptions(columnSelect, 'Year')
|
|
1725
1739
|
|
|
1726
1740
|
// Set custom label
|
|
1727
|
-
const
|
|
1728
|
-
const labelInput =
|
|
1741
|
+
const firstColumnConfig = await getFirstColumnConfig()
|
|
1742
|
+
const labelInput = await firstColumnConfig.findByLabelText(/^label$/i)
|
|
1729
1743
|
await userEvent.clear(labelInput)
|
|
1730
1744
|
await userEvent.type(labelInput, 'Report Year')
|
|
1731
1745
|
},
|
|
@@ -1741,39 +1755,42 @@ export const BarColumnsSectionTests: Story = {
|
|
|
1741
1755
|
await performAndAssert(
|
|
1742
1756
|
'Enable tooltip display and configure number formatting',
|
|
1743
1757
|
() => {
|
|
1744
|
-
const
|
|
1745
|
-
const
|
|
1758
|
+
const firstColumnSelect = canvas.queryAllByLabelText(/^column$/i)[0]
|
|
1759
|
+
const fieldset = firstColumnSelect?.closest('fieldset')
|
|
1760
|
+
const scopedFieldset = fieldset ? within(fieldset as HTMLElement) : null
|
|
1761
|
+
const tooltipCheckbox = scopedFieldset?.queryByLabelText(/show in tooltip/i) as HTMLInputElement | null
|
|
1762
|
+
const commasCheckbox = scopedFieldset?.queryByLabelText(/add commas to numbers/i) as HTMLInputElement | null
|
|
1763
|
+
const prefixInput = scopedFieldset?.queryByLabelText(/^prefix$/i) as HTMLInputElement | null
|
|
1764
|
+
const suffixInput = scopedFieldset?.queryByLabelText(/^suffix$/i) as HTMLInputElement | null
|
|
1746
1765
|
|
|
1747
1766
|
return {
|
|
1748
|
-
tooltipChecked:
|
|
1749
|
-
commasChecked:
|
|
1767
|
+
tooltipChecked: tooltipCheckbox?.checked || false,
|
|
1768
|
+
commasChecked: commasCheckbox?.checked || false,
|
|
1769
|
+
prefixValue: prefixInput?.value || '',
|
|
1770
|
+
suffixValue: suffixInput?.value || ''
|
|
1750
1771
|
}
|
|
1751
1772
|
},
|
|
1752
1773
|
async () => {
|
|
1774
|
+
const firstColumnConfig = await getFirstColumnConfig()
|
|
1775
|
+
|
|
1753
1776
|
// Enable tooltip display
|
|
1754
|
-
const
|
|
1755
|
-
const tooltipCheckbox = tooltipCheckboxes[0] as HTMLInputElement
|
|
1777
|
+
const tooltipCheckbox = (await firstColumnConfig.findByLabelText(/show in tooltip/i)) as HTMLInputElement
|
|
1756
1778
|
if (!tooltipCheckbox.checked) {
|
|
1757
1779
|
await userEvent.click(tooltipCheckbox)
|
|
1758
1780
|
}
|
|
1759
1781
|
|
|
1760
1782
|
// Enable commas for numbers
|
|
1761
|
-
const
|
|
1762
|
-
const commasCheckbox = commasCheckboxes[0] as HTMLInputElement
|
|
1783
|
+
const commasCheckbox = (await firstColumnConfig.findByLabelText(/add commas to numbers/i)) as HTMLInputElement
|
|
1763
1784
|
if (!commasCheckbox.checked) {
|
|
1764
1785
|
await userEvent.click(commasCheckbox)
|
|
1765
1786
|
}
|
|
1766
1787
|
|
|
1767
1788
|
// Add prefix and suffix
|
|
1768
|
-
const
|
|
1769
|
-
|
|
1770
|
-
const prefixInput = prefixInputs[1]
|
|
1771
|
-
|
|
1789
|
+
const prefixInput = await firstColumnConfig.findByLabelText(/^prefix$/i)
|
|
1772
1790
|
await userEvent.clear(prefixInput)
|
|
1773
1791
|
await userEvent.type(prefixInput, 'Year: ')
|
|
1774
1792
|
|
|
1775
|
-
const
|
|
1776
|
-
const suffixInput = suffixInputs[1]
|
|
1793
|
+
const suffixInput = await firstColumnConfig.findByLabelText(/^suffix$/i)
|
|
1777
1794
|
await userEvent.clear(suffixInput)
|
|
1778
1795
|
await userEvent.type(suffixInput, ' AD')
|
|
1779
1796
|
},
|
|
@@ -1781,6 +1798,8 @@ export const BarColumnsSectionTests: Story = {
|
|
|
1781
1798
|
// Checkboxes should be enabled
|
|
1782
1799
|
expect(after.tooltipChecked).toBe(true)
|
|
1783
1800
|
expect(after.commasChecked).toBe(true)
|
|
1801
|
+
expect(after.prefixValue).toBe('Year: ')
|
|
1802
|
+
expect(after.suffixValue).toBe(' AD')
|
|
1784
1803
|
|
|
1785
1804
|
return true
|
|
1786
1805
|
}
|
|
@@ -1905,7 +1924,7 @@ export const BarLegendTests: Story = {
|
|
|
1905
1924
|
const rightLegend = canvasElement.querySelector('.legend-container.right')
|
|
1906
1925
|
const bottomLegend = canvasElement.querySelector('.legend-container.bottom')
|
|
1907
1926
|
const topLegend = canvasElement.querySelector('.legend-container.top')
|
|
1908
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
1927
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
1909
1928
|
|
|
1910
1929
|
return {
|
|
1911
1930
|
hasLeftLegend: !!leftLegend,
|
|
@@ -2385,7 +2404,7 @@ export const BarFiltersTests: Story = {
|
|
|
2385
2404
|
// Helper function to get chart data visualization state
|
|
2386
2405
|
// Tests VISUALIZATION OUTPUT (filtered data in chart) not control state
|
|
2387
2406
|
const getChartDataState = () => {
|
|
2388
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
2407
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
2389
2408
|
const svg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
2390
2409
|
const bars = svg?.querySelectorAll('rect[class*="bar"], rect[data-testid*="bar"], g[class*="bar"] rect') || []
|
|
2391
2410
|
const filtersList = canvasElement.querySelector('.draggable-field-list')
|
|
@@ -2687,7 +2706,7 @@ export const BarVisualTests: Story = {
|
|
|
2687
2706
|
// Helper function to capture animation visualization state
|
|
2688
2707
|
const getAnimationVisualizationState = () => {
|
|
2689
2708
|
// Find the actual chart SVG, not UI icons or other SVGs
|
|
2690
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
2709
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
2691
2710
|
const chartSvg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
2692
2711
|
|
|
2693
2712
|
// Animation affects SVG classes and chart elements
|
|
@@ -2802,12 +2821,12 @@ export const BarVisualTests: Story = {
|
|
|
2802
2821
|
|
|
2803
2822
|
// Helper function to capture bar border visualization state
|
|
2804
2823
|
const getBarBorderVisualizationState = () => {
|
|
2805
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
2824
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
2806
2825
|
const chartSvg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
2807
2826
|
|
|
2808
2827
|
// Find bar elements in the chart
|
|
2809
2828
|
const barElements =
|
|
2810
|
-
chartSvg?.querySelectorAll('rect[class*="bar"], path[class*="bar"], g[class*="bar"]
|
|
2829
|
+
chartSvg?.querySelectorAll('rect[class*="bar"], path[class*="bar"], g[class*="bar"] path') || []
|
|
2811
2830
|
|
|
2812
2831
|
// Check for border-related styles and attributes
|
|
2813
2832
|
const barsWithStroke = Array.from(barElements).filter(bar => {
|
|
@@ -2910,10 +2929,11 @@ export const BarPatternSettingsTests: Story = {
|
|
|
2910
2929
|
type: 'continuous',
|
|
2911
2930
|
dataKey: 'y1'
|
|
2912
2931
|
},
|
|
2932
|
+
series: [{ dataKey: 'y1' }, { dataKey: 'y2' }, { dataKey: 'y3' }, { dataKey: 'y4' }],
|
|
2913
2933
|
// Override with data suitable for pattern testing
|
|
2914
2934
|
data: [
|
|
2915
2935
|
{ category: 'Q1', y1: 19000, y2: 47000, y3: 59000, y4: 91000 },
|
|
2916
|
-
{ category: 'Q2', y1: 18000, y2: 32000, y3:
|
|
2936
|
+
{ category: 'Q2', y1: 18000, y2: 32000, y3: 19000, y4: 89000 },
|
|
2917
2937
|
{ category: 'Q3', y1: 7000, y2: 38000, y3: 74000, y4: 89000 },
|
|
2918
2938
|
{ category: 'Q4', y1: 15000, y2: 41000, y3: 67000, y4: 95000 }
|
|
2919
2939
|
],
|
|
@@ -2938,7 +2958,7 @@ export const BarPatternSettingsTests: Story = {
|
|
|
2938
2958
|
|
|
2939
2959
|
// Helper function to capture SVG pattern visualization state
|
|
2940
2960
|
const getPatternVisualizationState = () => {
|
|
2941
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
2961
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
2942
2962
|
const chartSvg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
2943
2963
|
|
|
2944
2964
|
// Find SVG <defs> section with pattern definitions
|
|
@@ -2948,8 +2968,10 @@ export const BarPatternSettingsTests: Story = {
|
|
|
2948
2968
|
// Find pattern overlays (visual application of patterns)
|
|
2949
2969
|
const patternOverlays = chartSvg?.querySelectorAll('.pattern-overlay') || []
|
|
2950
2970
|
|
|
2951
|
-
// Find bars with pattern fills
|
|
2952
|
-
const barsWithPatterns = chartSvg?.querySelectorAll('rect
|
|
2971
|
+
// Find bars with pattern fills (works for both fragment refs and absolute URL refs)
|
|
2972
|
+
const barsWithPatterns = Array.from(chartSvg?.querySelectorAll('path, rect') || []).filter(shape =>
|
|
2973
|
+
(shape.getAttribute('fill') || '').includes('chart-pattern-')
|
|
2974
|
+
)
|
|
2953
2975
|
|
|
2954
2976
|
// Get pattern configuration UI state
|
|
2955
2977
|
const patternConfigSections = canvasElement.querySelectorAll('.accordion__panel .accordion .accordion__item')
|
|
@@ -3103,6 +3125,43 @@ export const BarPatternSettingsTests: Story = {
|
|
|
3103
3125
|
}
|
|
3104
3126
|
)
|
|
3105
3127
|
|
|
3128
|
+
await performAndAssert(
|
|
3129
|
+
'Clear Pattern Data Key - Existing data value applies across all series',
|
|
3130
|
+
getPatternVisualizationState,
|
|
3131
|
+
async () => {
|
|
3132
|
+
const dataKeyDropdown = canvasElement.querySelector('select[id*="pattern-datakey-"]') as HTMLSelectElement
|
|
3133
|
+
|
|
3134
|
+
if (dataKeyDropdown) {
|
|
3135
|
+
await userEvent.selectOptions(dataKeyDropdown, '')
|
|
3136
|
+
}
|
|
3137
|
+
},
|
|
3138
|
+
(before, after) => {
|
|
3139
|
+
// Clearing data key should keep value matching active and broaden the match across series.
|
|
3140
|
+
expect(after.hasBarsWithPatterns).toBe(true)
|
|
3141
|
+
expect(after.barsWithPatternsCount).toBeGreaterThan(before.barsWithPatternsCount)
|
|
3142
|
+
|
|
3143
|
+
return true
|
|
3144
|
+
}
|
|
3145
|
+
)
|
|
3146
|
+
|
|
3147
|
+
await performAndAssert(
|
|
3148
|
+
'Clear Pattern Data Value - Pattern stops rendering when value is empty',
|
|
3149
|
+
getPatternVisualizationState,
|
|
3150
|
+
async () => {
|
|
3151
|
+
const dataValueInput = canvasElement.querySelector('input[id*="pattern-datavalue-"]') as HTMLInputElement
|
|
3152
|
+
|
|
3153
|
+
if (dataValueInput) {
|
|
3154
|
+
await userEvent.clear(dataValueInput)
|
|
3155
|
+
}
|
|
3156
|
+
},
|
|
3157
|
+
(before, after) => {
|
|
3158
|
+
expect(before.barsWithPatternsCount).toBeGreaterThan(0)
|
|
3159
|
+
expect(after.barsWithPatternsCount).toBe(0)
|
|
3160
|
+
|
|
3161
|
+
return true
|
|
3162
|
+
}
|
|
3163
|
+
)
|
|
3164
|
+
|
|
3106
3165
|
// ========================================================================
|
|
3107
3166
|
// Test Pattern Size Configuration - Pattern Density Changes
|
|
3108
3167
|
// Tests how pattern size affects visual pattern rendering
|
|
@@ -3402,7 +3461,7 @@ export const BarTextAnnotationsTests: Story = {
|
|
|
3402
3461
|
|
|
3403
3462
|
// Helper function to capture SVG annotation visualization state
|
|
3404
3463
|
const getAnnotationVisualizationState = () => {
|
|
3405
|
-
const chartContainer = canvasElement.querySelector('.cove-
|
|
3464
|
+
const chartContainer = canvasElement.querySelector('.cove-visualization__body, .chart-container, .visualization')
|
|
3406
3465
|
const chartSvg = chartContainer?.querySelector('svg') || canvasElement.querySelector('svg:not(.icon)')
|
|
3407
3466
|
|
|
3408
3467
|
// Find annotation accordion sections (nested accordions for each annotation)
|
|
@@ -121,7 +121,12 @@ export const BrushDefaultSelectionTests: Story = {
|
|
|
121
121
|
const getBrushSelectionState = () => {
|
|
122
122
|
// The brush selection is represented by the visx-brush extent rect
|
|
123
123
|
const brushExtent = canvasElement.querySelector('.visx-brush rect[class*="selection"]') as SVGRectElement
|
|
124
|
-
const brushSvg =
|
|
124
|
+
const brushSvg =
|
|
125
|
+
(brushExtent?.closest('svg') as SVGSVGElement) ||
|
|
126
|
+
(canvasElement.querySelector('.visx-brush svg') as SVGSVGElement)
|
|
127
|
+
const brushWidthAttr = brushSvg ? parseFloat(brushSvg.getAttribute('width') || '0') : 0
|
|
128
|
+
const totalBrushWidth = brushSvg ? brushSvg.clientWidth || brushWidthAttr : 0
|
|
129
|
+
const countInput = canvasElement.querySelector('input[id*="brushDefaultRecentDateCount"]') as HTMLInputElement
|
|
125
130
|
|
|
126
131
|
// Get the visible data points in the main chart (lines or bars)
|
|
127
132
|
const chartSvg = canvasElement.querySelector('.linear-chart svg, .cove-chart svg') as SVGSVGElement
|
|
@@ -130,11 +135,12 @@ export const BrushDefaultSelectionTests: Story = {
|
|
|
130
135
|
return {
|
|
131
136
|
brushWidth: brushExtent ? parseFloat(brushExtent.getAttribute('width') || '0') : 0,
|
|
132
137
|
brushX: brushExtent ? parseFloat(brushExtent.getAttribute('x') || '0') : 0,
|
|
133
|
-
totalBrushWidth
|
|
138
|
+
totalBrushWidth,
|
|
134
139
|
visibleDataPoints: dataPointsInChart,
|
|
140
|
+
defaultRecentDateCountValue: countInput?.value || '',
|
|
135
141
|
selectionPercentage:
|
|
136
|
-
brushExtent &&
|
|
137
|
-
? (parseFloat(brushExtent.getAttribute('width') || '0') /
|
|
142
|
+
brushExtent && totalBrushWidth > 0
|
|
143
|
+
? (parseFloat(brushExtent.getAttribute('width') || '0') / totalBrushWidth) * 100
|
|
138
144
|
: 0
|
|
139
145
|
}
|
|
140
146
|
}
|
|
@@ -176,7 +182,7 @@ export const BrushDefaultSelectionTests: Story = {
|
|
|
176
182
|
},
|
|
177
183
|
(before, after) => {
|
|
178
184
|
// Changing from 30 to 50 should expand the brush width
|
|
179
|
-
return after.brushWidth > before.brushWidth
|
|
185
|
+
return after.defaultRecentDateCountValue === '50' && after.brushWidth > before.brushWidth
|
|
180
186
|
}
|
|
181
187
|
)
|
|
182
188
|
|
|
@@ -226,26 +232,6 @@ export const BrushDefaultSelectionTests: Story = {
|
|
|
226
232
|
expect(afterSettingCount.dataPointCount).toBeGreaterThan(0)
|
|
227
233
|
expect(afterSettingCount.dataPointCount).toBeLessThanOrEqual(35) // 30 + tolerance
|
|
228
234
|
}
|
|
229
|
-
|
|
230
|
-
// ============================================================================
|
|
231
|
-
// TEST: Clear Recent Date Count Returns to Default 35%
|
|
232
|
-
// Verifies: When the count is cleared, brush returns to percentage-based default
|
|
233
|
-
// ============================================================================
|
|
234
|
-
|
|
235
|
-
await performAndAssert(
|
|
236
|
-
'Clear Default Recent Date Count (return to 35%)',
|
|
237
|
-
getBrushSelectionState,
|
|
238
|
-
async () => {
|
|
239
|
-
await userEvent.clear(recentDateCountInput)
|
|
240
|
-
await userEvent.tab()
|
|
241
|
-
},
|
|
242
|
-
(before, after) => {
|
|
243
|
-
// The selection should return to approximately 35% of the total width
|
|
244
|
-
// Since we had set it to 30 points (~9% with 329 data points),
|
|
245
|
-
// clearing should expand it back to ~35%
|
|
246
|
-
return after.brushWidth > before.brushWidth || after.selectionPercentage > before.selectionPercentage
|
|
247
|
-
}
|
|
248
|
-
)
|
|
249
235
|
}
|
|
250
236
|
}
|
|
251
237
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import Chart from '../CdcChartComponent'
|
|
3
|
+
import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
|
|
4
|
+
import brushContinuousConfig from './_mock/brush_continuous.json'
|
|
5
|
+
import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Chart> = {
|
|
8
|
+
title: 'Components/Templates/Chart/BrushSlider/Matrix/Continuous',
|
|
9
|
+
component: Chart
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default meta
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof Chart>
|
|
15
|
+
|
|
16
|
+
export const Default: Story = {
|
|
17
|
+
args: { config: brushContinuousConfig, isEditor: false },
|
|
18
|
+
parameters: {
|
|
19
|
+
docs: {
|
|
20
|
+
description: { story: 'xAxis.type = "continuous", default ascending numeric order.' }
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
play: async ({ canvasElement }) => {
|
|
24
|
+
await assertVisualizationRendered(canvasElement)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const Reversed: Story = {
|
|
29
|
+
args: {
|
|
30
|
+
config: editConfigKeys(brushContinuousConfig, [{ path: ['xAxis', 'sortByRecentDate'], value: true }]),
|
|
31
|
+
isEditor: false
|
|
32
|
+
},
|
|
33
|
+
parameters: {
|
|
34
|
+
docs: {
|
|
35
|
+
description: { story: 'xAxis.type = "continuous", sortByRecentDate = true.' }
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
play: async ({ canvasElement }) => {
|
|
39
|
+
await assertVisualizationRendered(canvasElement)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import Chart from '../CdcChartComponent'
|
|
3
|
+
import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
|
|
4
|
+
import brushDateLargeConfig from './_mock/brush_date_large.json'
|
|
5
|
+
import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
|
|
6
|
+
|
|
7
|
+
// Helper: add a "Category" column to every row (duplicating for two categories) and add a dropdown filter
|
|
8
|
+
function addFilter(config: any) {
|
|
9
|
+
const dataWithCategory = [
|
|
10
|
+
...config.data.map((row: any) => ({ ...row, Category: 'Group A' })),
|
|
11
|
+
...config.data.map((row: any) => ({ ...row, Category: 'Group B' }))
|
|
12
|
+
]
|
|
13
|
+
return editConfigKeys(config, [
|
|
14
|
+
{ path: ['data'], value: dataWithCategory },
|
|
15
|
+
{
|
|
16
|
+
path: ['filters'],
|
|
17
|
+
value: [
|
|
18
|
+
{
|
|
19
|
+
values: ['Group A', 'Group B'],
|
|
20
|
+
filterStyle: 'dropdown',
|
|
21
|
+
showDropdown: false,
|
|
22
|
+
active: 'Group A',
|
|
23
|
+
columnName: 'Category',
|
|
24
|
+
orderedValues: ['Group A', 'Group B'],
|
|
25
|
+
defaultValue: 'Group A'
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
])
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const reversedDataConfig = editConfigKeys(brushDateLargeConfig, [
|
|
33
|
+
{ path: ['data'], value: [...brushDateLargeConfig.data].reverse() }
|
|
34
|
+
])
|
|
35
|
+
|
|
36
|
+
const meta: Meta<typeof Chart> = {
|
|
37
|
+
title: 'Components/Templates/Chart/BrushSlider/Matrix/Date',
|
|
38
|
+
component: Chart
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default meta
|
|
42
|
+
|
|
43
|
+
type Story = StoryObj<typeof Chart>
|
|
44
|
+
|
|
45
|
+
export const Default: Story = {
|
|
46
|
+
args: { config: brushDateLargeConfig, isEditor: false },
|
|
47
|
+
parameters: {
|
|
48
|
+
docs: {
|
|
49
|
+
description: {
|
|
50
|
+
story: 'xAxis.type = "date", default chronological order. ~104 weekly data points.'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
play: async ({ canvasElement }) => {
|
|
55
|
+
await assertVisualizationRendered(canvasElement)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const Reversed: Story = {
|
|
60
|
+
args: {
|
|
61
|
+
config: editConfigKeys(brushDateLargeConfig, [{ path: ['xAxis', 'sortByRecentDate'], value: true }]),
|
|
62
|
+
isEditor: false
|
|
63
|
+
},
|
|
64
|
+
parameters: {
|
|
65
|
+
docs: {
|
|
66
|
+
description: { story: 'xAxis.type = "date", sortByRecentDate = true. Most recent dates appear first.' }
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
play: async ({ canvasElement }) => {
|
|
70
|
+
await assertVisualizationRendered(canvasElement)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const ReversedDataOrder: Story = {
|
|
75
|
+
args: { config: reversedDataConfig, isEditor: false },
|
|
76
|
+
parameters: {
|
|
77
|
+
docs: {
|
|
78
|
+
description: {
|
|
79
|
+
story:
|
|
80
|
+
'Data array in reverse chronological order (newest-first in JSON). Verifies the brush sorts its domain correctly regardless of input order.'
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
play: async ({ canvasElement }) => {
|
|
85
|
+
await assertVisualizationRendered(canvasElement)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const WithFilter: Story = {
|
|
90
|
+
args: { config: addFilter(brushDateLargeConfig), isEditor: false },
|
|
91
|
+
parameters: {
|
|
92
|
+
docs: {
|
|
93
|
+
description: { story: 'xAxis.type = "date" with a dropdown filter applied.' }
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
play: async ({ canvasElement }) => {
|
|
97
|
+
await assertVisualizationRendered(canvasElement)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const Reversed_WithFilter: Story = {
|
|
102
|
+
args: {
|
|
103
|
+
config: addFilter(editConfigKeys(brushDateLargeConfig, [{ path: ['xAxis', 'sortByRecentDate'], value: true }])),
|
|
104
|
+
isEditor: false
|
|
105
|
+
},
|
|
106
|
+
parameters: {
|
|
107
|
+
docs: {
|
|
108
|
+
description: { story: 'sortByRecentDate = true with a dropdown filter.' }
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
play: async ({ canvasElement }) => {
|
|
112
|
+
await assertVisualizationRendered(canvasElement)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import Chart from '../CdcChartComponent'
|
|
3
|
+
import { editConfigKeys } from '@cdc/core/helpers/configHelpers'
|
|
4
|
+
import brushEnabledConfig from './_mock/brush_enabled.json'
|
|
5
|
+
import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
|
|
6
|
+
|
|
7
|
+
// Helper: add a "Category" column to every row (duplicating for two categories) and add a dropdown filter
|
|
8
|
+
function addFilter(config: any) {
|
|
9
|
+
const dataWithCategory = [
|
|
10
|
+
...config.data.map((row: any) => ({ ...row, Category: 'Group A' })),
|
|
11
|
+
...config.data.map((row: any) => ({ ...row, Category: 'Group B' }))
|
|
12
|
+
]
|
|
13
|
+
return editConfigKeys(config, [
|
|
14
|
+
{ path: ['data'], value: dataWithCategory },
|
|
15
|
+
{
|
|
16
|
+
path: ['filters'],
|
|
17
|
+
value: [
|
|
18
|
+
{
|
|
19
|
+
values: ['Group A', 'Group B'],
|
|
20
|
+
filterStyle: 'dropdown',
|
|
21
|
+
showDropdown: false,
|
|
22
|
+
active: 'Group A',
|
|
23
|
+
columnName: 'Category',
|
|
24
|
+
orderedValues: ['Group A', 'Group B'],
|
|
25
|
+
defaultValue: 'Group A'
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
])
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const meta: Meta<typeof Chart> = {
|
|
33
|
+
title: 'Components/Templates/Chart/BrushSlider/Matrix/DateTime',
|
|
34
|
+
component: Chart
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default meta
|
|
38
|
+
|
|
39
|
+
type Story = StoryObj<typeof Chart>
|
|
40
|
+
|
|
41
|
+
export const Default: Story = {
|
|
42
|
+
args: { config: brushEnabledConfig, isEditor: false },
|
|
43
|
+
parameters: {
|
|
44
|
+
docs: {
|
|
45
|
+
description: { story: 'xAxis.type = "date-time", default chronological order.' }
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
play: async ({ canvasElement }) => {
|
|
49
|
+
await assertVisualizationRendered(canvasElement)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const Reversed: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
config: editConfigKeys(brushEnabledConfig, [{ path: ['xAxis', 'sortByRecentDate'], value: true }]),
|
|
56
|
+
isEditor: false
|
|
57
|
+
},
|
|
58
|
+
parameters: {
|
|
59
|
+
docs: {
|
|
60
|
+
description: { story: 'xAxis.type = "date-time", sortByRecentDate = true.' }
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
play: async ({ canvasElement }) => {
|
|
64
|
+
await assertVisualizationRendered(canvasElement)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const WithFilter: Story = {
|
|
69
|
+
args: { config: addFilter(brushEnabledConfig), isEditor: false },
|
|
70
|
+
parameters: {
|
|
71
|
+
docs: {
|
|
72
|
+
description: { story: 'xAxis.type = "date-time" with a dropdown filter applied.' }
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
play: async ({ canvasElement }) => {
|
|
76
|
+
await assertVisualizationRendered(canvasElement)
|
|
77
|
+
}
|
|
78
|
+
}
|