@cdc/core 4.26.1 → 4.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/.claude/agents/qa-test-developer.md +126 -0
  2. package/CLAUDE.local.md +67 -0
  3. package/_stories/Gallery.Charts.stories.tsx +34 -41
  4. package/_stories/Gallery.DataBite.stories.tsx +14 -7
  5. package/_stories/Gallery.Maps.stories.tsx +36 -27
  6. package/_stories/Gallery.WaffleChart.stories.tsx +1 -1
  7. package/_stories/PageART.stories.tsx +4 -3
  8. package/_stories/PageBRFSS.stories.tsx +20 -15
  9. package/_stories/PageCancerRegistries.stories.tsx +14 -14
  10. package/_stories/PageEasternEquineEncephalitis.stories.tsx +30 -16
  11. package/_stories/PageExcessiveAlcoholUse.stories.tsx +148 -143
  12. package/_stories/PageMaternalMortality.stories.tsx +4 -3
  13. package/_stories/PageOralHealth.stories.tsx +14 -9
  14. package/_stories/PageSmokingTobacco.stories.tsx +14 -9
  15. package/_stories/PageStateDiabetesProfiles.stories.tsx +14 -9
  16. package/_stories/PageWastewater.stories.tsx +40 -26
  17. package/_stories/VegaImport.stories.tsx +401 -0
  18. package/_stories/vega-fixtures/bars-with-line.json +444 -0
  19. package/_stories/vega-fixtures/bars.json +58 -0
  20. package/_stories/vega-fixtures/combo-bar-rolling-mean.json +88 -0
  21. package/_stories/vega-fixtures/combo.json +68 -0
  22. package/_stories/vega-fixtures/grouped-horizontal-bars.json +83 -0
  23. package/_stories/vega-fixtures/grouped-horizontal-bars2.json +231 -0
  24. package/_stories/vega-fixtures/horizontal-bar.json +427 -0
  25. package/_stories/vega-fixtures/horizontal-bars-with-bad-colors.json +197 -0
  26. package/_stories/vega-fixtures/horizontal-bars2.json +58 -0
  27. package/_stories/vega-fixtures/lines.json +227 -0
  28. package/_stories/vega-fixtures/measles-bars.json +348 -0
  29. package/_stories/vega-fixtures/measles-map.json +11101 -0
  30. package/_stories/vega-fixtures/measles-stacked-bars.json +2147 -0
  31. package/_stories/vega-fixtures/multi-dataset.json +255 -0
  32. package/_stories/vega-fixtures/no-data.json +14 -0
  33. package/_stories/vega-fixtures/pie-chart.json +94 -0
  34. package/_stories/vega-fixtures/repeat-spec.json +47 -0
  35. package/_stories/vega-fixtures/stacked-area.json +222 -0
  36. package/_stories/vega-fixtures/stacked-bar-with-rect.json +3412 -0
  37. package/_stories/vega-fixtures/stacked-bars-with-line.json +364 -0
  38. package/_stories/vega-fixtures/stacked-bars.json +212 -0
  39. package/_stories/vega-fixtures/stacked-horizontal-bars.json +140 -0
  40. package/_stories/vega-fixtures/warning-combo.json +59 -0
  41. package/_stories/vega-fixtures/warning-scatter-and-line.json +1182 -0
  42. package/assets/icon-chart-area.svg +1 -0
  43. package/assets/icon-chart-radar.svg +23 -0
  44. package/assets/logo2.svg +31 -0
  45. package/components/AdvancedEditor/EmbedEditor.tsx +270 -38
  46. package/components/CustomColorsEditor/CustomColorsEditor.tsx +3 -10
  47. package/components/DataTable/helpers/getSeriesName.ts +6 -0
  48. package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +14 -6
  49. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +4 -0
  50. package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +33 -29
  51. package/components/Layout/components/Sidebar/components/sidebar.styles.scss +2 -2
  52. package/components/Layout/components/Visualization/index.tsx +11 -0
  53. package/components/MediaControls.tsx +0 -1
  54. package/components/_stories/CustomColorsEditor.stories.tsx +37 -0
  55. package/components/_stories/DataTable.stories.tsx +1 -0
  56. package/data/colorPalettes.ts +18 -5
  57. package/data/mapColorPalettes.ts +10 -0
  58. package/devTemplate/dev.js +235 -0
  59. package/devTemplate/index.html +30 -0
  60. package/devTemplate/preview.html +1503 -0
  61. package/devTemplate/sidebar.css +151 -0
  62. package/dist/cove-main.css +2803 -4471
  63. package/dist/cove-main.css.map +1 -1
  64. package/generateViteConfig.js +111 -2
  65. package/helpers/DataTransform.ts +1 -5
  66. package/helpers/cove/date.ts +33 -1
  67. package/helpers/cove/string.ts +29 -0
  68. package/helpers/coveUpdateWorker.ts +3 -1
  69. package/helpers/embed/embedCodeGenerator.ts +80 -0
  70. package/helpers/embed/embedHelper.js +158 -0
  71. package/helpers/embed/filterUtils.ts +121 -0
  72. package/helpers/embed/index.ts +21 -0
  73. package/helpers/embed/urlValidation.ts +119 -0
  74. package/helpers/filterVizData.ts +6 -1
  75. package/helpers/getFileExtension.ts +0 -6
  76. package/helpers/metrics/types.ts +3 -0
  77. package/helpers/palettes/colorDistributions.ts +1 -1
  78. package/helpers/palettes/utils.ts +12 -12
  79. package/helpers/parseCsvWithQuotes.ts +15 -14
  80. package/helpers/prepareScreenshot.ts +27 -7
  81. package/helpers/testing.ts +44 -0
  82. package/helpers/tests/DataTransform.test.ts +125 -0
  83. package/helpers/tests/date.test.ts +64 -0
  84. package/helpers/vegaConfig.ts +1 -1
  85. package/helpers/vegaConfigImport.ts +160 -0
  86. package/helpers/ver/4.26.1.ts +1 -1
  87. package/helpers/ver/4.26.2.ts +84 -0
  88. package/helpers/ver/tests/4.26.1.test.ts +105 -0
  89. package/helpers/ver/tests/4.26.2.test.ts +298 -0
  90. package/helpers/viewports.ts +2 -0
  91. package/package.json +27 -32
  92. package/styles/v2/components/editor.scss +9 -9
  93. package/styles/v2/utils/_grid.scss +8 -3
  94. package/types/Annotation.ts +10 -11
  95. package/types/General.ts +2 -0
  96. package/types/Palette.ts +21 -0
  97. package/types/Visualization.ts +6 -0
  98. package/_stories/StoryRenderingTests.stories.tsx +0 -164
  99. package/helpers/embedCodeGenerator.ts +0 -109
@@ -1,164 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite'
2
- import { within, expect } from 'storybook/test'
3
- import { performAndAssert } from '@cdc/core/helpers/testing'
4
-
5
- const ChartRenderingValidator = () => (
6
- <div data-testid='chart-rendering-validator'>
7
- <h2>Simple COVE Visualization Tests</h2>
8
- <p>This test validates all stories load and render.</p>
9
- </div>
10
- )
11
-
12
- const meta: Meta<typeof ChartRenderingValidator> = {
13
- title: 'Testing/Story Rendering Tests',
14
- component: ChartRenderingValidator,
15
- parameters: {
16
- layout: 'fullscreen'
17
- },
18
- tags: ['!dev', '!autodocs']
19
- }
20
-
21
- export default meta
22
- type Story = StoryObj<typeof ChartRenderingValidator>
23
-
24
- /**
25
- * Fetch all stories from Storybook's JSON API and filter for visualization stories
26
- * @returns Promise that resolves to an array of story URLs to test
27
- */
28
- const getVisualizationStoryUrls = async (): Promise<string[]> => {
29
- let response
30
- try {
31
- response = await fetch('http://localhost:6006/index.json')
32
- } catch (error) {
33
- console.error('Error fetching visualization story URLs:', error)
34
- return []
35
- }
36
-
37
- const data = await response.json()
38
-
39
- const storyUrls: string[] = []
40
-
41
- Object.values(data.entries).forEach((story: any) => {
42
- if (story.type === 'story') {
43
- const isVisualizationStory =
44
- story.title.includes('Components/Templates/') &&
45
- !story.name.toLowerCase().includes('test') &&
46
- !story.title.includes('Guide')
47
-
48
- if (isVisualizationStory) {
49
- const iframeUrl = `http://localhost:6006/iframe.html?id=${story.id}`
50
- storyUrls.push(iframeUrl)
51
- }
52
- }
53
- })
54
- return storyUrls
55
- }
56
-
57
- /**
58
- * Convert iframe URL to Storybook story URL for better debugging
59
- * @param iframeUrl - The iframe URL (e.g., 'http://localhost:6006/iframe.html?id=components-templates-chart--multiple-lines')
60
- * @returns The Storybook story URL (e.g., 'http://localhost:6006/?path=/story/components-templates-chart--multiple-lines')
61
- */
62
- const iframeUrlToStoryUrl = (iframeUrl: string): string => {
63
- const url = new URL(iframeUrl)
64
- const storyId = url.searchParams.get('id')
65
- return `http://localhost:6006/?path=/story/${storyId}`
66
- }
67
-
68
- /**
69
- * Test a single Storybook iframe URL for successful visualization rendering
70
- * @param iframeUrl - The complete iframe URL to test (e.g., 'http://localhost:6006/iframe.html?id=...')
71
- * @returns Promise that resolves with test results
72
- */
73
- const testIframeVisualization = async (iframeUrl: string) => {
74
- iframeUrl = iframeUrl
75
-
76
- const iframe = document.createElement('iframe')
77
- iframe.style.width = '1200px'
78
- iframe.style.height = '800px'
79
- iframe.src = iframeUrl
80
- document.body.appendChild(iframe)
81
-
82
- try {
83
- await performAndAssert(
84
- 'Wait for iframe to load',
85
- () => {
86
- try {
87
- const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document
88
- return {
89
- loaded: !!iframeDoc && iframeDoc.readyState !== 'loading',
90
- readyState: iframeDoc?.readyState || 'unknown'
91
- }
92
- } catch (error: any) {
93
- return { loaded: false, readyState: 'error', error: error.message }
94
- }
95
- },
96
- async () => {},
97
- (before, after) => {
98
- return after.loaded
99
- }
100
- )
101
-
102
- await performAndAssert(
103
- 'Wait for SVG elements to render in iframe',
104
- () => {
105
- try {
106
- const iframeDoc = iframe?.contentDocument || iframe?.contentWindow?.document
107
- if (!iframeDoc) return { svgCount: 0, hasCoveModule: false, error: 'No document access' }
108
-
109
- const svgCount = iframeDoc.querySelectorAll('svg').length
110
- const hasCoveModule = !!iframeDoc.querySelector('.cdc-open-viz-module')
111
- const isDataBite = !!iframeDoc.querySelector('.bite-content')
112
- const isDataTable = !!iframeDoc.querySelector('.data-table')
113
-
114
- return { svgCount, hasCoveModule, isDataBite, isDataTable, error: null }
115
- } catch (error: any) {
116
- return { svgCount: 0, hasCoveModule: false, isDataBite: false, isDataTable: false, error: error.message }
117
- }
118
- },
119
- async () => {},
120
- (before, after) => {
121
- return (after.svgCount > 0 && after.hasCoveModule) || after.isDataBite || after.isDataTable
122
- }
123
- )
124
- } finally {
125
- if (iframe.parentNode) {
126
- document.body.removeChild(iframe)
127
- }
128
- }
129
- }
130
-
131
- export const StoryRenderingTests: Story = {
132
- play: async ({ canvasElement }) => {
133
- const canvas = within(canvasElement)
134
- expect(canvas.getByTestId('chart-rendering-validator')).toBeInTheDocument()
135
-
136
- const storyUrls = await getVisualizationStoryUrls()
137
-
138
- if (storyUrls.length === 0) {
139
- console.warn('No visualization stories found to test')
140
- return
141
- }
142
-
143
- const results: { iframeUrl: string; storyUrl: string; success: boolean; error?: string }[] = []
144
-
145
- for (const [i, iframeUrl] of storyUrls.entries()) {
146
- const storyUrl = iframeUrlToStoryUrl(iframeUrl)
147
-
148
- try {
149
- await testIframeVisualization(iframeUrl)
150
- results.push({ iframeUrl, storyUrl, success: true })
151
- } catch (error: any) {
152
- if (i > 0) {
153
- results.push({ iframeUrl, storyUrl, success: false, error: error.message })
154
- }
155
- }
156
- }
157
-
158
- const failed = results.filter(r => !r.success).length
159
-
160
- if (failed > 0) {
161
- throw new Error(`${failed} out of ${storyUrls.length} visualization stories failed to render`)
162
- }
163
- }
164
- }
@@ -1,109 +0,0 @@
1
- /**
2
- * Generates iframe embed code for COVE visualizations
3
- * Used by editor's "Share with Partners" feature
4
- */
5
-
6
- interface EmbedCodeOptions {
7
- configUrl: string
8
- width?: string
9
- height?: string
10
- embedBaseUrl?: string
11
- helperScriptUrl?: string
12
- /** Additional URL parameters (e.g., filter values, hide flags) */
13
- urlParams?: Record<string, string>
14
- }
15
-
16
- /**
17
- * Detect if we're in development mode
18
- */
19
- export function isDevMode(): boolean {
20
- if (typeof window === 'undefined') return false
21
- return window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
22
- }
23
-
24
- /**
25
- * Get default embed base URL based on environment
26
- * Returns full absolute URL including protocol and host
27
- */
28
- export function getDefaultEmbedBaseUrl(): string {
29
- if (isDevMode()) {
30
- return 'http://localhost:8080'
31
- }
32
- return 'https://www.cdc.gov/TemplatePackage/contrib/widgets/openVizWrapper/dist/embed/embed.html'
33
- }
34
-
35
- /**
36
- * Get embed path (without protocol/host) for same-origin usage
37
- * Use this for preview iframes on the same domain
38
- */
39
- export function getEmbedPath(): string {
40
- if (isDevMode()) {
41
- return '/'
42
- }
43
- return '/TemplatePackage/contrib/widgets/openVizWrapper/dist/embed/embed.html'
44
- }
45
-
46
- /**
47
- * Get default embed helper script URL based on environment
48
- */
49
- export function getDefaultHelperScriptUrl(): string {
50
- if (isDevMode()) {
51
- return 'http://localhost:8080/src/embed-helper/index.js'
52
- }
53
- return 'https://www.cdc.gov/TemplatePackage/contrib/widgets/openVizWrapper/dist/embed/embed-helper.js'
54
- }
55
-
56
- /**
57
- * Get default generator base URL based on environment
58
- */
59
- export function getDefaultGeneratorBaseUrl(): string {
60
- if (isDevMode()) {
61
- return 'http://localhost:8080/generator.html'
62
- }
63
- return 'https://www.cdc.gov/TemplatePackage/contrib/widgets/openVizWrapper/dist/embed/generator.html'
64
- }
65
-
66
- /**
67
- * Generate basic iframe embed code for partners
68
- *
69
- * @param options.configUrl - URL to the published config JSON
70
- * @param options.width - iframe width (default: "100%")
71
- * @param options.height - iframe height (default: "300")
72
- * @param options.embedBaseUrl - Base URL for embed page (auto-detected by environment)
73
- * @param options.helperScriptUrl - URL for embed-helper.js (auto-detected by environment)
74
- * @param options.urlParams - Additional URL parameters (e.g., filter values, hide flags)
75
- * @returns HTML string with iframe and script tag
76
- */
77
- export function generateEmbedCode(options: EmbedCodeOptions): string {
78
- const {
79
- configUrl,
80
- width = '100%',
81
- height = '300',
82
- embedBaseUrl = getDefaultEmbedBaseUrl(),
83
- helperScriptUrl = getDefaultHelperScriptUrl(),
84
- urlParams = {}
85
- } = options
86
-
87
- // Construct embed page URL with config parameter and any additional params
88
- const params = new URLSearchParams()
89
- params.set('configUrl', configUrl)
90
-
91
- // Add any additional URL parameters (filters, hide flags, etc.)
92
- Object.entries(urlParams).forEach(([key, value]) => {
93
- if (value) params.set(key, value)
94
- })
95
-
96
- const embedUrl = `${embedBaseUrl}?${params.toString()}`
97
-
98
- // Generate iframe code
99
- const iframeCode = `<iframe src="${embedUrl}"
100
- data-cove-embed
101
- width="${width}"
102
- height="${height}"
103
- frameborder="0"
104
- title="CDC Data Visualization"
105
- ></iframe>
106
- <script src="${helperScriptUrl}"></script>`
107
-
108
- return iframeCode
109
- }