@cdc/markup-include 4.26.2 → 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.
@@ -1,5 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { expect } from 'storybook/test'
2
3
  import CdcMarkupInclude from '../CdcMarkupInclude'
4
+ import { assertVisualizationRendered } from '@cdc/core/helpers/testing'
3
5
  import primary from './_mock/primary.json'
4
6
  import noConditions from './_mock/no-conditions.json'
5
7
  import withConditions from './_mock/with-conditions.json'
@@ -48,6 +50,63 @@ export const icon_no_text: Story = {
48
50
  isEditor: false
49
51
  }
50
52
  }
53
+
54
+ export const Icon_Sizing: Story = {
55
+ args: {
56
+ config: {
57
+ ...primary,
58
+ contentEditor: {
59
+ ...primary.contentEditor,
60
+ showHeader: true,
61
+ title: 'SVG icon sizing',
62
+ useInlineHTML: true,
63
+ markupVariables: [
64
+ {
65
+ sourceType: 'icon',
66
+ name: 'link-external',
67
+ tag: '{{link-external}}',
68
+ iconId: 'link-external',
69
+ conditions: []
70
+ }
71
+ ],
72
+ inlineHTML: `
73
+ <p class="icon-sizing-inline">Rate <span class="icon-sizing-inline-target">{{link-external}}</span> increased</p>
74
+ <div
75
+ class="icon-sizing-parent-target"
76
+ data-cove-svg-size="parent-height"
77
+ style="height: 200px; background: #f8d7da; display: inline-flex; align-items: center;"
78
+ >
79
+ {{link-external}}
80
+ </div>
81
+ `
82
+ },
83
+ enableMarkupVariables: true
84
+ } as any,
85
+ isEditor: false
86
+ },
87
+ play: async ({ canvasElement }) => {
88
+ await assertVisualizationRendered(canvasElement)
89
+
90
+ const inlineIcon = canvasElement.querySelector('.icon-sizing-inline-target .cove-inline-svg') as HTMLElement | null
91
+ const parentIcon = canvasElement.querySelector('.icon-sizing-parent-target .cove-inline-svg') as HTMLElement | null
92
+ const parentContainer = canvasElement.querySelector('.icon-sizing-parent-target') as HTMLElement | null
93
+
94
+ expect(inlineIcon).toBeTruthy()
95
+ expect(parentIcon).toBeTruthy()
96
+ expect(parentContainer).toBeTruthy()
97
+
98
+ const inlineHeight = inlineIcon!.getBoundingClientRect().height
99
+ const parentHeight = parentIcon!.getBoundingClientRect().height
100
+ const containerHeight = parentContainer!.getBoundingClientRect().height
101
+
102
+ expect(inlineHeight).toBeGreaterThan(0)
103
+ expect(inlineHeight).toBeLessThan(50)
104
+ expect(parentHeight).toBeGreaterThan(inlineHeight * 3)
105
+ expect(parentHeight).toBeGreaterThan(180)
106
+ expect(Math.abs(parentHeight - containerHeight)).toBeLessThan(2)
107
+ }
108
+ }
109
+
51
110
  export const image_with_text: Story = {
52
111
  args: {
53
112
  config: imageWithText,
@@ -55,4 +114,26 @@ export const image_with_text: Story = {
55
114
  }
56
115
  }
57
116
 
117
+ export const TP5_Test: Story = {
118
+ args: {
119
+ config: {
120
+ ...primary,
121
+ contentEditor: {
122
+ ...primary.contentEditor,
123
+ style: 'tp5',
124
+ title: 'TP5 Markup Include Test',
125
+ useInlineHTML: true,
126
+ inlineHTML:
127
+ '<p>This is a TP5 style markup include test story.</p><p>Clear the title in the editor to verify TP5 title hide behavior.</p>'
128
+ },
129
+ visual: {
130
+ ...primary.visual,
131
+ border: true,
132
+ whiteBackground: true
133
+ }
134
+ },
135
+ isEditor: true
136
+ }
137
+ }
138
+
58
139
  export default meta
@@ -1,39 +1,43 @@
1
- .cdc-open-viz-module.markup-include {
1
+ .cove-visualization.markup-include {
2
2
  .spacing-wrapper {
3
3
  background-color: var(--lightGray) !important;
4
4
  }
5
+
5
6
  .cove-tooltip-variable {
6
7
  display: none;
7
8
  }
8
9
 
9
- .markup-include-content-container.cove-component__content {
10
- .markup-include-component.cove-component__content:not(.component--hideBackgroundColor, .component--has-background) {
10
+ c .markup-include-content-container.cove-visualization__inner {
11
+ .markup-include-component.cove-visualization__body:not(.component--hide-background-color, .component--has-background) {
11
12
  background-color: white;
12
13
  }
13
14
  }
14
15
  }
15
16
 
16
- .cdc-open-viz-module.markup-include.isEditor {
17
+ .cove-visualization.markup-include.is-editor {
17
18
  .cove-tooltip-variable {
18
- position: relative;
19
- display: inline;
20
19
  background: var(--orange-tertiary);
20
+ display: inline;
21
+ position: relative;
22
+
21
23
  .cove-tooltip-value {
22
- display: none;
23
- position: absolute;
24
24
  background: var(--white);
25
25
  border: 1px solid black;
26
+ display: none;
26
27
  font-size: 16px;
28
+ max-width: 500px;
27
29
  padding: 10px;
30
+ position: absolute;
28
31
  width: 100vw;
29
- max-width: 500px;
30
32
  z-index: 9999;
31
33
  }
32
- &:hover > .cove-tooltip-value {
34
+
35
+ &:hover>.cove-tooltip-value {
33
36
  display: block;
34
37
  }
35
38
  }
39
+
36
40
  .cove-markup-include-variable-value {
37
41
  display: none !important;
38
42
  }
39
- }
43
+ }
@@ -1,4 +1,4 @@
1
- .cdc-open-viz-module.markup-include {
1
+ .cove-visualization.markup-include {
2
2
  .need-data-source-prompt {
3
3
  color: var(--gray);
4
4
  font-size: 0.8rem;
@@ -1,10 +1,11 @@
1
- import { useContext, useRef } from 'react'
1
+ import { useContext, useMemo, useRef } from 'react'
2
2
 
3
3
  // Context
4
4
  import ConfigContext from '../../ConfigContext'
5
5
 
6
6
  // Helpers
7
7
  import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
8
+ import { useDataColumns } from '@cdc/core/hooks/useDataColumns'
8
9
 
9
10
  // Components
10
11
  import { EditorPanel as BaseEditorPanel } from '@cdc/core/components/EditorPanel/EditorPanel'
@@ -14,7 +15,11 @@ import Icon from '@cdc/core/components/ui/Icon'
14
15
  import Tooltip from '@cdc/core/components/ui/Tooltip'
15
16
  import MarkupVariablesEditor from '@cdc/core/components/EditorPanel/components/MarkupVariablesEditor'
16
17
  import FootnotesEditor from '@cdc/core/components/EditorPanel/FootnotesEditor'
17
- import { VisualSection } from '@cdc/core/components/EditorPanel/sections/VisualSection'
18
+ import StyleTreatmentSection from '@cdc/core/components/EditorPanel/sections/StyleTreatmentSection'
19
+ import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
20
+ import { DataColorSelector } from '@cdc/core/components/DataColorSelector'
21
+ import { DATA_COLOR_PRESETS } from '@cdc/core/helpers/dataColors'
22
+ import Button from '@cdc/core/components/elements/Button'
18
23
  import { Datasets } from '@cdc/core/types/DataSet'
19
24
 
20
25
  // styles
@@ -25,10 +30,120 @@ type MarkupIncludeEditorPanelProps = {
25
30
  }
26
31
 
27
32
  const EditorPanel: React.FC<MarkupIncludeEditorPanelProps> = ({ datasets }) => {
28
- const { config, data, isDashboard, loading, setParentConfig, updateConfig } = useContext(ConfigContext)
29
- const { contentEditor, theme, visual } = config
33
+ const { config, data, editorData, isDashboard, loading, setParentConfig, updateConfig } = useContext(ConfigContext)
34
+ const { contentEditor, theme, visual } = config || {}
30
35
  const { inlineHTML, srcUrl, title, useInlineHTML } = contentEditor || {}
36
+ const isTp5Style = contentEditor?.style === 'tp5'
31
37
  const updateField = updateFieldFactory(config, updateConfig, true)
38
+ const styleTreatment = (visual as any)?.tp5Treatment ? 'tp5' : 'legacy'
39
+ const markupEditorData = Array.isArray(editorData) ? editorData : data || []
40
+ const columns = useDataColumns(markupEditorData)
41
+ const dataColorMappings = config.dataColors?.mappings || []
42
+
43
+ const dataColorValues = useMemo(() => {
44
+ const colorColumn = config.dataColors?.column
45
+ if (!colorColumn) return []
46
+
47
+ const uniqueValues = new Set<string>()
48
+ markupEditorData?.forEach(row => {
49
+ const value = row?.[colorColumn]
50
+ if (value !== undefined && value !== null) {
51
+ uniqueValues.add(String(value))
52
+ }
53
+ })
54
+
55
+ return Array.from(uniqueValues).sort()
56
+ }, [markupEditorData, config.dataColors?.column])
57
+
58
+ type DataColorDisplayEntry = { sourceValue: string; fromData: boolean; key: string }
59
+
60
+ const dataColorDisplayList = useMemo<DataColorDisplayEntry[]>(() => {
61
+ const dataSet = new Set(dataColorValues)
62
+ const list: DataColorDisplayEntry[] = dataColorValues.map(v => ({
63
+ sourceValue: v,
64
+ fromData: true,
65
+ key: `data-${v}`
66
+ }))
67
+ dataColorMappings.forEach((m, i) => {
68
+ if (!dataSet.has(m.sourceValue)) {
69
+ list.push({ sourceValue: m.sourceValue, fromData: false, key: `custom-${i}` })
70
+ }
71
+ })
72
+ return list
73
+ }, [dataColorValues, dataColorMappings])
74
+
75
+ const updateDataColorMapping = (sourceValue: string, color: string) => {
76
+ const nextMappings = [...dataColorMappings]
77
+ const existingIndex = nextMappings.findIndex(m => m.sourceValue === sourceValue)
78
+
79
+ if (!color) {
80
+ if (existingIndex > -1) {
81
+ nextMappings.splice(existingIndex, 1)
82
+ }
83
+ } else {
84
+ const nextMapping = { sourceValue, color }
85
+ if (existingIndex > -1) {
86
+ nextMappings[existingIndex] = nextMapping
87
+ } else {
88
+ nextMappings.push(nextMapping)
89
+ }
90
+ }
91
+
92
+ updateConfig({
93
+ ...config,
94
+ dataColors: {
95
+ ...config.dataColors,
96
+ mappings: nextMappings
97
+ }
98
+ })
99
+ }
100
+
101
+ const addCustomDataColorMapping = () => {
102
+ const nextMappings = [...dataColorMappings, { sourceValue: '', color: DATA_COLOR_PRESETS[0] }]
103
+ updateConfig({
104
+ ...config,
105
+ dataColors: {
106
+ ...config.dataColors,
107
+ mappings: nextMappings
108
+ }
109
+ })
110
+ }
111
+
112
+ const updateDataColorMappingValue = (oldValue: string, newValue: string) => {
113
+ const nextMappings = dataColorMappings.map(m => (m.sourceValue === oldValue ? { ...m, sourceValue: newValue } : m))
114
+ updateConfig({
115
+ ...config,
116
+ dataColors: {
117
+ ...config.dataColors,
118
+ mappings: nextMappings
119
+ }
120
+ })
121
+ }
122
+
123
+ const removeDataColorMapping = (sourceValue: string) => {
124
+ const nextMappings = dataColorMappings.filter(m => m.sourceValue !== sourceValue)
125
+ updateConfig({
126
+ ...config,
127
+ dataColors: {
128
+ ...config.dataColors,
129
+ mappings: nextMappings
130
+ }
131
+ })
132
+ }
133
+
134
+ const handleStyleTreatmentChange = (value: string) => {
135
+ const useTp5Treatment = value === 'tp5'
136
+ updateConfig({
137
+ ...config,
138
+ visual: {
139
+ ...config.visual,
140
+ tp5Treatment: useTp5Treatment,
141
+ border: useTp5Treatment ? false : config.visual?.border,
142
+ borderColorTheme: useTp5Treatment ? false : config.visual?.borderColorTheme,
143
+ accent: useTp5Treatment ? false : config.visual?.accent
144
+ }
145
+ })
146
+ }
32
147
 
33
148
  const textAreaInEditorContainer = useRef(null)
34
149
 
@@ -58,6 +173,17 @@ const EditorPanel: React.FC<MarkupIncludeEditorPanelProps> = ({ datasets }) => {
58
173
  {() => (
59
174
  <Accordion>
60
175
  <Accordion.Section title='General'>
176
+ <Select
177
+ value={contentEditor?.style || 'default'}
178
+ section='contentEditor'
179
+ fieldName='style'
180
+ label='Style'
181
+ updateField={updateField}
182
+ options={[
183
+ { value: 'default', label: 'Default' },
184
+ { value: 'tp5', label: 'TP5' }
185
+ ]}
186
+ />
61
187
  <TextField
62
188
  value={title || ''}
63
189
  section='contentEditor'
@@ -66,16 +192,42 @@ const EditorPanel: React.FC<MarkupIncludeEditorPanelProps> = ({ datasets }) => {
66
192
  placeholder='Markup Include Title'
67
193
  updateField={updateField}
68
194
  />
195
+ {!isTp5Style && (
196
+ <Select
197
+ value={contentEditor?.titleStyle || 'small'}
198
+ section='contentEditor'
199
+ fieldName='titleStyle'
200
+ label='Title Style'
201
+ updateField={updateField}
202
+ options={[
203
+ { value: 'small', label: 'Small (h3)' },
204
+ { value: 'large', label: 'Large (h2)' },
205
+ { value: 'legacy', label: 'Legacy' }
206
+ ]}
207
+ tooltip={
208
+ <Tooltip style={{ textTransform: 'none' }}>
209
+ <Tooltip.Target>
210
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
211
+ </Tooltip.Target>
212
+ <Tooltip.Content>
213
+ <p>Choose the visual style for the title.</p>
214
+ <p>
215
+ Consider heading order on your page when selecting the title style. For 508 reasons, ensure your
216
+ page follows a proper heading order.
217
+ </p>
218
+ </Tooltip.Content>
219
+ </Tooltip>
220
+ }
221
+ />
222
+ )}
69
223
  <Select
70
- value={contentEditor.titleStyle || 'small'}
71
- section='contentEditor'
72
- fieldName='titleStyle'
73
- label='Title Style'
224
+ value={config.locale}
225
+ fieldName='locale'
226
+ label='Language for dates and numbers'
74
227
  updateField={updateField}
75
228
  options={[
76
- { value: 'small', label: 'Small (h3)' },
77
- { value: 'large', label: 'Large (h2)' },
78
- { value: 'legacy', label: 'Legacy' }
229
+ { value: 'en-US', label: 'English (en-US)' },
230
+ { value: 'es-MX', label: 'Spanish (es-MX)' }
79
231
  ]}
80
232
  tooltip={
81
233
  <Tooltip style={{ textTransform: 'none' }}>
@@ -83,10 +235,9 @@ const EditorPanel: React.FC<MarkupIncludeEditorPanelProps> = ({ datasets }) => {
83
235
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
84
236
  </Tooltip.Target>
85
237
  <Tooltip.Content>
86
- <p>Choose the visual style for the title.</p>
87
238
  <p>
88
- Consider heading order on your page when selecting the title style. For 508 reasons, ensure your
89
- page follows a proper heading order.
239
+ Change the language (locale) for this visualization to alter the way dates and numbers are
240
+ formatted.
90
241
  </p>
91
242
  </Tooltip.Content>
92
243
  </Tooltip>
@@ -131,8 +282,111 @@ const EditorPanel: React.FC<MarkupIncludeEditorPanelProps> = ({ datasets }) => {
131
282
  </div>
132
283
  </Accordion.Section>
133
284
  <Accordion.Section title='Visual'>
134
- <VisualSection config={config} updateField={updateField} updateConfig={updateConfig} />
285
+ {!isTp5Style && (
286
+ <HeaderThemeSelector
287
+ selectedTheme={config.theme}
288
+ onThemeSelect={theme => updateConfig({ ...config, theme })}
289
+ />
290
+ )}
291
+ {isTp5Style ? (
292
+ <CheckBox
293
+ value={visual?.whiteBackground}
294
+ section='visual'
295
+ fieldName='whiteBackground'
296
+ label='Use White Background Style'
297
+ updateField={updateField}
298
+ />
299
+ ) : (
300
+ <StyleTreatmentSection
301
+ styleTreatment={styleTreatment}
302
+ onStyleTreatmentChange={handleStyleTreatmentChange}
303
+ showStyleTreatment={false}
304
+ border={config.visual?.border}
305
+ borderColorTheme={config.visual?.borderColorTheme}
306
+ accent={config.visual?.accent}
307
+ background={config.visual?.background}
308
+ hideBackgroundColor={config.visual?.hideBackgroundColor}
309
+ showBackground
310
+ showHideBackgroundColor
311
+ updateField={updateField}
312
+ />
313
+ )}
135
314
  </Accordion.Section>
315
+ {isTp5Style && (
316
+ <Accordion.Section title='Data-Driven Colors'>
317
+ <Select
318
+ value={config.dataColors?.column || ''}
319
+ section='dataColors'
320
+ fieldName='column'
321
+ label='Color Column'
322
+ updateField={updateField}
323
+ initial='Select'
324
+ options={columns}
325
+ tooltip={
326
+ <Tooltip style={{ textTransform: 'none' }}>
327
+ <Tooltip.Target>
328
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
329
+ </Tooltip.Target>
330
+ <Tooltip.Content>
331
+ <p>
332
+ Choose a column whose values determine the background color of this visualization. Map each
333
+ value to a color below. Text color adjusts automatically for contrast.
334
+ </p>
335
+ </Tooltip.Content>
336
+ </Tooltip>
337
+ }
338
+ />
339
+ {config.dataColors?.column && dataColorDisplayList.length > 0 && (
340
+ <div className='mt-2'>
341
+ {dataColorDisplayList.map(({ sourceValue, fromData, key }) => {
342
+ const selectedColor = dataColorMappings.find(m => m.sourceValue === sourceValue)?.color || ''
343
+
344
+ return (
345
+ <div className='cove-accordion__panel-row align-center mb-2' key={key}>
346
+ <div className='cove-accordion__panel-col' style={{ flex: '1 1 0', minWidth: 0 }}>
347
+ {fromData ? (
348
+ sourceValue
349
+ ) : (
350
+ <input
351
+ type='text'
352
+ value={sourceValue}
353
+ placeholder='Enter value'
354
+ style={{ width: '100%' }}
355
+ onChange={e => updateDataColorMappingValue(sourceValue, e.target.value)}
356
+ />
357
+ )}
358
+ </div>
359
+ <div className='cove-accordion__panel-col' style={{ flex: '0 0 4.5rem' }}>
360
+ <DataColorSelector
361
+ value={selectedColor}
362
+ onChange={color => updateDataColorMapping(sourceValue, color)}
363
+ />
364
+ </div>
365
+ <div className='cove-accordion__panel-col' style={{ flex: '0 0 1.5rem' }}>
366
+ {!fromData && (
367
+ <button
368
+ type='button'
369
+ className='btn btn-danger'
370
+ style={{ padding: '0.15rem 0.45rem', lineHeight: 1 }}
371
+ title='Remove mapping'
372
+ onClick={() => removeDataColorMapping(sourceValue)}
373
+ >
374
+
375
+ </button>
376
+ )}
377
+ </div>
378
+ </div>
379
+ )
380
+ })}
381
+ </div>
382
+ )}
383
+ {config.dataColors?.column && (
384
+ <Button type='button' onClick={addCustomDataColorMapping} className='btn btn-primary full-width mt-3'>
385
+ Add Color Mapping
386
+ </Button>
387
+ )}
388
+ </Accordion.Section>
389
+ )}
136
390
  {isDashboard && (
137
391
  <Accordion.Section title='Footnotes'>
138
392
  <FootnotesEditor config={config} updateField={updateField} datasets={datasets} />
@@ -141,12 +395,13 @@ const EditorPanel: React.FC<MarkupIncludeEditorPanelProps> = ({ datasets }) => {
141
395
  <Accordion.Section title='Markup Variables'>
142
396
  <MarkupVariablesEditor
143
397
  markupVariables={config.markupVariables || []}
144
- data={data || []}
398
+ data={markupEditorData}
145
399
  datasets={datasets}
146
400
  config={config}
147
401
  onChange={handleMarkupVariablesChange}
148
402
  enableMarkupVariables={config.enableMarkupVariables || false}
149
403
  onToggleEnable={handleToggleEnable}
404
+ dataMetadata={config.dataMetadata}
150
405
  />
151
406
  </Accordion.Section>
152
407
  </Accordion>
@@ -2,6 +2,7 @@ export default {
2
2
  contentEditor: {
3
3
  inlineHTML: '<strong>Inline HTML</strong>',
4
4
  showHeader: true,
5
+ style: 'default',
5
6
  srcUrl: '#example',
6
7
  title: '',
7
8
  titleStyle: 'small',
@@ -22,7 +23,12 @@ export default {
22
23
  accent: false,
23
24
  background: false,
24
25
  hideBackgroundColor: false,
25
- borderColorTheme: false
26
+ borderColorTheme: false,
27
+ whiteBackground: false
28
+ },
29
+ dataColors: {
30
+ column: '',
31
+ mappings: []
26
32
  },
27
33
  markupVariables: [],
28
34
  enableMarkupVariables: false
@@ -1,17 +1,80 @@
1
- .markup-include {
2
- .cove-component__content-wrap {
3
- padding: 0;
1
+ @import '@cdc/core/styles/layout/wrapper-padding';
4
2
 
5
- &.has-top-padding {
6
- padding-top: 1rem;
7
- padding-bottom: 1rem;
3
+ .cove-visualization.type-markup-include {
4
+ .cove-visualization__body {
5
+ @include cove-visualization-body-padding;
6
+ }
7
+
8
+ .markup-include-component--tp5 {
9
+ padding: 0 !important;
10
+ border: none !important;
11
+ background: none !important;
12
+ container-type: inline-size;
13
+
14
+ .markup-include-tp5 {
15
+ gap: 0.7rem;
16
+ box-shadow: 0 2px 4px rgb(159 159 159 / 10%);
17
+ border: 1px solid var(--colors-cyan-15, #dff2f6) !important;
18
+ margin: 0 !important;
19
+ padding: 1.25rem;
20
+ border-radius: 0.25rem;
21
+ background-color: var(--colors-cyan-10, #eff9fa);
22
+ }
23
+
24
+ .cdc-callout__heading {
25
+ width: 100%;
26
+ font-size: 1.1rem;
27
+ }
28
+
29
+ .cdc-callout__body {
30
+ flex-wrap: nowrap;
31
+ flex: auto;
32
+ }
33
+
34
+ @container (max-width: 576px) {
35
+ .cdc-callout__body {
36
+ flex-wrap: wrap;
37
+ }
8
38
  }
9
39
 
10
- &.has-side-padding {
11
- padding-left: 1rem;
12
- padding-right: 1rem;
40
+ .cdc-callout__content {
41
+ font-size: 1rem;
13
42
  }
14
43
 
44
+ .cdc-callout--data-color {
45
+ .cdc-callout__heading,
46
+ .cdc-callout__content {
47
+ color: inherit;
48
+ }
49
+ }
50
+
51
+ &.white-background-style {
52
+ .markup-include-tp5 {
53
+ border: 1px solid #009ec1 !important;
54
+ background: transparent;
55
+ box-shadow: 0 2px 4px rgb(159 159 159 / 10%);
56
+ }
57
+
58
+ .cdc-callout--data-color {
59
+ border: none !important;
60
+ }
61
+ }
62
+
63
+ &.white-background-style.display-border {
64
+ .markup-include-tp5 {
65
+ box-shadow: 0 2px 4px rgb(159 159 159 / 10%);
66
+ }
67
+ }
68
+
69
+ .cove-visualization__body-wrap,
70
+ .cove-visualization__content-section {
71
+ padding: 0;
72
+ }
73
+ }
74
+
75
+ .cove-visualization__body-wrap {
76
+ @include cove-visualization-body-wrap-inline-padding;
77
+
15
78
  h1,
16
79
  h2,
17
80
  h3 {
@@ -22,9 +85,16 @@
22
85
  margin-top: auto;
23
86
  margin-bottom: auto;
24
87
  }
88
+
89
+ // keep markup include images inlines on dashboards
90
+ // e.g. requested to help here: https://www.cdc.gov/fluview/surveillance/2026-week-10.html
91
+ // needed for backwards compatibility with existing dashboards, but also to prevent any future issues with images in markup include visualizations being forced to display as blocks
92
+ span > img {
93
+ display: inline;
94
+ }
25
95
  }
26
96
 
27
- .cove-component__content.component--hideBackgroundColor {
97
+ .cove-visualization__body.component--hide-background-color {
28
98
  background: transparent;
29
99
  }
30
100
 
@@ -47,6 +117,7 @@
47
117
  float: left;
48
118
  }
49
119
  }
120
+
50
121
  .cove-editor .cove-editor__content {
51
122
  padding-left: 350px;
52
123
  display: flex;