@cdc/markup-include 4.26.4 → 4.26.5
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 +18 -18
- package/LICENSE +201 -0
- package/dist/cdcmarkupinclude.js +10613 -12387
- package/package.json +3 -3
- package/src/CdcMarkupInclude.tsx +13 -15
- package/src/_stories/MarkupInclude.stories.tsx +40 -0
- package/src/cdcMarkupInclude.style.css +9 -6
- package/src/components/EditorPanel/EditorPanel.tsx +4 -8
- package/src/index.tsx +6 -3
- package/src/scss/main.scss +1 -6
- package/src/test/CdcMarkupInclude.test.jsx +104 -4
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/markup-include",
|
|
3
|
-
"version": "4.26.
|
|
3
|
+
"version": "4.26.5",
|
|
4
4
|
"description": "React component for displaying HTML content from an outside link",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Rob Shelnutt <rob@blackairplane.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.5",
|
|
10
10
|
"axios": "^1.13.2",
|
|
11
11
|
"dompurify": "^3.4.0",
|
|
12
12
|
"lodash": "^4.17.23",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"vite-plugin-css-injected-by-js": "^2.4.0",
|
|
20
20
|
"vite-plugin-svgr": "^4.2.0"
|
|
21
21
|
},
|
|
22
|
-
"gitHead": "
|
|
22
|
+
"gitHead": "61c025165d96b45a6002c34582c5a622a9d865a9",
|
|
23
23
|
"homepage": "https://github.com/CDCgov/cdc-open-viz#readme",
|
|
24
24
|
"main": "dist/cdcmarkupinclude",
|
|
25
25
|
"moduleName": "CdcMarkupInclude",
|
package/src/CdcMarkupInclude.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useEffect, useCallback, useRef, useReducer, useMemo } from 'react'
|
|
2
2
|
// external
|
|
3
3
|
import DOMPurify from 'dompurify'
|
|
4
|
-
import axios from 'axios'
|
|
5
4
|
import parse from 'html-react-parser'
|
|
6
5
|
|
|
7
6
|
// cdc
|
|
@@ -9,6 +8,7 @@ import { MarkupIncludeConfig } from '@cdc/core/types/MarkupInclude'
|
|
|
9
8
|
import { publish } from '@cdc/core/helpers/events'
|
|
10
9
|
import { processMarkupVariables } from '@cdc/core/helpers/markupProcessor'
|
|
11
10
|
import { addValuesToFilters } from '@cdc/core/helpers/addValuesToFilters'
|
|
11
|
+
import { hasVisibleVizFilters } from '@cdc/core/helpers/filterVisibility'
|
|
12
12
|
import { resolveDataColor } from '@cdc/core/helpers/dataColors'
|
|
13
13
|
import ConfigContext from './ConfigContext'
|
|
14
14
|
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
@@ -201,20 +201,18 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
201
201
|
dispatch({ type: 'SET_URL_MARKUP', payload })
|
|
202
202
|
} else {
|
|
203
203
|
try {
|
|
204
|
-
await
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
const res = await fetch(srcUrl)
|
|
205
|
+
if (!res.ok) {
|
|
206
|
+
dispatch({ type: 'SET_MARKUP_ERROR', payload: res.status })
|
|
207
|
+
dispatch({ type: 'SET_URL_MARKUP', payload: '' })
|
|
208
|
+
} else {
|
|
209
|
+
const data = await res.text()
|
|
210
|
+
if (data) {
|
|
211
|
+
dispatch({ type: 'SET_URL_MARKUP', payload: data })
|
|
207
212
|
}
|
|
208
|
-
})
|
|
209
|
-
} catch (err) {
|
|
210
|
-
if (err.response) {
|
|
211
|
-
// Response with error
|
|
212
|
-
dispatch({ type: 'SET_MARKUP_ERROR', payload: err.response.status })
|
|
213
|
-
} else if (err.request) {
|
|
214
|
-
// No response received
|
|
215
|
-
dispatch({ type: 'SET_MARKUP_ERROR', payload: 200 })
|
|
216
213
|
}
|
|
217
|
-
|
|
214
|
+
} catch {
|
|
215
|
+
dispatch({ type: 'SET_MARKUP_ERROR', payload: 200 })
|
|
218
216
|
dispatch({ type: 'SET_URL_MARKUP', payload: '' })
|
|
219
217
|
}
|
|
220
218
|
}
|
|
@@ -346,7 +344,7 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
346
344
|
shouldApplyTopPadding ? ' has-top-padding' : ''
|
|
347
345
|
}${shouldApplySidePadding ? ' has-side-padding' : ''}`.trim()}
|
|
348
346
|
filters={
|
|
349
|
-
config.filters
|
|
347
|
+
hasVisibleVizFilters(config.filters) ? (
|
|
350
348
|
<Filters
|
|
351
349
|
config={config}
|
|
352
350
|
setFilters={setFilters}
|
|
@@ -354,7 +352,7 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
354
352
|
dimensions={[0, 0]}
|
|
355
353
|
interactionLabel={interactionLabel || 'markup-include'}
|
|
356
354
|
/>
|
|
357
|
-
) :
|
|
355
|
+
) : undefined
|
|
358
356
|
}
|
|
359
357
|
header={
|
|
360
358
|
!isTp5Style ? (
|
|
@@ -136,4 +136,44 @@ export const TP5_Test: Story = {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
export const Bootstrap_Grid_Mockup: Story = {
|
|
140
|
+
args: {
|
|
141
|
+
config: {
|
|
142
|
+
...primary,
|
|
143
|
+
contentEditor: {
|
|
144
|
+
...primary.contentEditor,
|
|
145
|
+
showHeader: true,
|
|
146
|
+
title: 'Bootstrap grid include mock',
|
|
147
|
+
useInlineHTML: true,
|
|
148
|
+
inlineHTML: `
|
|
149
|
+
<div class="row">
|
|
150
|
+
<div class="col-8">
|
|
151
|
+
<p><strong>col-8</strong> block inside markup include content.</p>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="col-3">
|
|
154
|
+
<p><strong>col-3</strong> block inside markup include content.</p>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
`
|
|
158
|
+
}
|
|
159
|
+
} as any,
|
|
160
|
+
isEditor: false
|
|
161
|
+
},
|
|
162
|
+
play: async ({ canvasElement }) => {
|
|
163
|
+
await assertVisualizationRendered(canvasElement)
|
|
164
|
+
|
|
165
|
+
const shell = canvasElement.querySelector('.cove-visualization.type-markup-include')
|
|
166
|
+
const contentSection = canvasElement.querySelector('.cove-visualization__content-section')
|
|
167
|
+
const primaryColumn = canvasElement.querySelector('.col-8')
|
|
168
|
+
const secondaryColumn = canvasElement.querySelector('.col-3')
|
|
169
|
+
|
|
170
|
+
expect(shell).toBeTruthy()
|
|
171
|
+
expect(contentSection).toBeTruthy()
|
|
172
|
+
expect(primaryColumn).toBeTruthy()
|
|
173
|
+
expect(secondaryColumn).toBeTruthy()
|
|
174
|
+
expect(primaryColumn?.closest('.cove-visualization__content-section')).toBe(contentSection)
|
|
175
|
+
expect(secondaryColumn?.closest('.cove-visualization__content-section')).toBe(contentSection)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
139
179
|
export default meta
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.cove-visualization.markup-include {
|
|
1
|
+
.cove-visualization.type-markup-include {
|
|
2
2
|
.spacing-wrapper {
|
|
3
3
|
background-color: var(--lightGray) !important;
|
|
4
4
|
}
|
|
@@ -7,14 +7,17 @@
|
|
|
7
7
|
display: none;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
.markup-include-component.cove-visualization__body:not(
|
|
10
|
+
.markup-include-content-container.cove-visualization__inner {
|
|
11
|
+
.markup-include-component.cove-visualization__body:not(
|
|
12
|
+
.component--hide-background-color,
|
|
13
|
+
.component--has-background
|
|
14
|
+
) {
|
|
12
15
|
background-color: white;
|
|
13
16
|
}
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
19
|
|
|
17
|
-
.cove-visualization.markup-include.is-editor {
|
|
20
|
+
.cove-visualization.type-markup-include.is-editor {
|
|
18
21
|
.cove-tooltip-variable {
|
|
19
22
|
background: var(--orange-tertiary);
|
|
20
23
|
display: inline;
|
|
@@ -32,7 +35,7 @@
|
|
|
32
35
|
z-index: 9999;
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
&:hover
|
|
38
|
+
&:hover > .cove-tooltip-value {
|
|
36
39
|
display: block;
|
|
37
40
|
}
|
|
38
41
|
}
|
|
@@ -40,4 +43,4 @@
|
|
|
40
43
|
.cove-markup-include-variable-value {
|
|
41
44
|
display: none !important;
|
|
42
45
|
}
|
|
43
|
-
}
|
|
46
|
+
}
|
|
@@ -16,6 +16,7 @@ import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
|
16
16
|
import MarkupVariablesEditor from '@cdc/core/components/EditorPanel/components/MarkupVariablesEditor'
|
|
17
17
|
import FootnotesEditor from '@cdc/core/components/EditorPanel/FootnotesEditor'
|
|
18
18
|
import StyleTreatmentSection from '@cdc/core/components/EditorPanel/sections/StyleTreatmentSection'
|
|
19
|
+
import { Tp5VisualSection } from '@cdc/core/components/EditorPanel/sections/Tp5VisualSection'
|
|
19
20
|
import { HeaderThemeSelector } from '@cdc/core/components/HeaderThemeSelector'
|
|
20
21
|
import { DataColorSelector } from '@cdc/core/components/DataColorSelector'
|
|
21
22
|
import { DATA_COLOR_PRESETS } from '@cdc/core/helpers/dataColors'
|
|
@@ -289,13 +290,7 @@ const EditorPanel: React.FC<MarkupIncludeEditorPanelProps> = ({ datasets }) => {
|
|
|
289
290
|
/>
|
|
290
291
|
)}
|
|
291
292
|
{isTp5Style ? (
|
|
292
|
-
<
|
|
293
|
-
value={visual?.whiteBackground}
|
|
294
|
-
section='visual'
|
|
295
|
-
fieldName='whiteBackground'
|
|
296
|
-
label='Use White Background Style'
|
|
297
|
-
updateField={updateField}
|
|
298
|
-
/>
|
|
293
|
+
<Tp5VisualSection config={config} updateField={updateField} />
|
|
299
294
|
) : (
|
|
300
295
|
<StyleTreatmentSection
|
|
301
296
|
styleTreatment={styleTreatment}
|
|
@@ -395,7 +390,8 @@ const EditorPanel: React.FC<MarkupIncludeEditorPanelProps> = ({ datasets }) => {
|
|
|
395
390
|
<Accordion.Section title='Markup Variables'>
|
|
396
391
|
<MarkupVariablesEditor
|
|
397
392
|
markupVariables={config.markupVariables || []}
|
|
398
|
-
data={
|
|
393
|
+
data={Array.isArray(data) ? data : []}
|
|
394
|
+
editorData={markupEditorData}
|
|
399
395
|
datasets={datasets}
|
|
400
396
|
config={config}
|
|
401
397
|
onChange={handleMarkupVariablesChange}
|
package/src/index.tsx
CHANGED
|
@@ -9,14 +9,17 @@ import CdcMarkupInclude from './CdcMarkupInclude'
|
|
|
9
9
|
|
|
10
10
|
let isEditor = window.location.href.includes('editor=true')
|
|
11
11
|
|
|
12
|
-
let domContainer = document.getElementsByClassName('react-container')[0]
|
|
12
|
+
let domContainer = document.getElementsByClassName('react-container')[0] as HTMLElement & { coveConfig?: any }
|
|
13
|
+
let configUrl = domContainer.dataset.configUrl
|
|
14
|
+
let injectedConfig = domContainer.coveConfig
|
|
13
15
|
|
|
14
16
|
ReactDOM.createRoot(domContainer).render(
|
|
15
17
|
<React.StrictMode>
|
|
16
18
|
<GlobalContextProvider>
|
|
17
19
|
<CdcMarkupInclude
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
config={injectedConfig}
|
|
21
|
+
configUrl={injectedConfig ? undefined : configUrl}
|
|
22
|
+
interactionLabel={configUrl}
|
|
20
23
|
isEditor={isEditor}
|
|
21
24
|
/>
|
|
22
25
|
</GlobalContextProvider>
|
package/src/scss/main.scss
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@import '@cdc/core/styles/layout/wrapper-padding';
|
|
2
|
+
@import '@cdc/core/styles/layout/callout';
|
|
2
3
|
|
|
3
4
|
.cove-visualization.type-markup-include {
|
|
4
5
|
.cove-visualization__body {
|
|
@@ -13,12 +14,6 @@
|
|
|
13
14
|
|
|
14
15
|
.markup-include-tp5 {
|
|
15
16
|
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
17
|
}
|
|
23
18
|
|
|
24
19
|
.cdc-callout__heading {
|
|
@@ -2,13 +2,18 @@ import path from 'node:path'
|
|
|
2
2
|
import fs from 'node:fs'
|
|
3
3
|
import vm from 'node:vm'
|
|
4
4
|
import React from 'react'
|
|
5
|
-
import { render, screen } from '@testing-library/react'
|
|
5
|
+
import { render, screen, waitFor } from '@testing-library/react'
|
|
6
6
|
import { testStandaloneBuild } from '@cdc/core/helpers/tests/testStandaloneBuild.ts'
|
|
7
7
|
import { describe, it, expect, vi } from 'vitest'
|
|
8
8
|
import CdcMarkupInclude from '../CdcMarkupInclude'
|
|
9
9
|
|
|
10
10
|
vi.mock('@cdc/core/components/EditorPanel/components/MarkupVariablesEditor', () => ({
|
|
11
|
-
default: ({ data }) =>
|
|
11
|
+
default: ({ data, editorData }) => (
|
|
12
|
+
<div>
|
|
13
|
+
<div data-testid='markup-variables-editor-data'>{JSON.stringify(data)}</div>
|
|
14
|
+
<div data-testid='markup-variables-editor-editor-data'>{JSON.stringify(editorData)}</div>
|
|
15
|
+
</div>
|
|
16
|
+
)
|
|
12
17
|
}))
|
|
13
18
|
|
|
14
19
|
const extractMarkedExampleConfig = (content, label) => {
|
|
@@ -28,7 +33,7 @@ describe('Markup Include', () => {
|
|
|
28
33
|
expect(result).toBe(true)
|
|
29
34
|
}, 300000)
|
|
30
35
|
|
|
31
|
-
it('uses dashboard rawData for markup variable editor choices when editing', async () => {
|
|
36
|
+
it('uses dashboard rawData for markup variable editor choices while preserving render data when editing', async () => {
|
|
32
37
|
const filteredData = [{ category: 'Filtered only' }]
|
|
33
38
|
const fullData = [{ category: 'Value A' }, { category: 'Value B' }]
|
|
34
39
|
|
|
@@ -65,7 +70,102 @@ describe('Markup Include', () => {
|
|
|
65
70
|
/>
|
|
66
71
|
)
|
|
67
72
|
|
|
68
|
-
expect(JSON.parse((await screen.findByTestId('markup-variables-editor-data')).textContent)).toEqual(
|
|
73
|
+
expect(JSON.parse((await screen.findByTestId('markup-variables-editor-data')).textContent)).toEqual(filteredData)
|
|
74
|
+
expect(JSON.parse((await screen.findByTestId('markup-variables-editor-editor-data')).textContent)).toEqual(fullData)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('does not render the visualization filters section when every markup include filter is hidden', async () => {
|
|
78
|
+
const { container } = render(
|
|
79
|
+
<CdcMarkupInclude
|
|
80
|
+
config={{
|
|
81
|
+
type: 'markup-include',
|
|
82
|
+
theme: 'theme-blue',
|
|
83
|
+
data: [{ state: 'Alabama' }],
|
|
84
|
+
filters: [
|
|
85
|
+
{
|
|
86
|
+
columnName: 'state',
|
|
87
|
+
values: ['Alabama'],
|
|
88
|
+
showDropdown: false,
|
|
89
|
+
id: 1,
|
|
90
|
+
parents: [],
|
|
91
|
+
active: 'Alabama',
|
|
92
|
+
filterStyle: 'dropdown',
|
|
93
|
+
label: 'State',
|
|
94
|
+
order: 'asc',
|
|
95
|
+
type: 'url'
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
markupVariables: [],
|
|
99
|
+
contentEditor: {
|
|
100
|
+
title: '',
|
|
101
|
+
inlineHTML: '<p>Example</p>',
|
|
102
|
+
useInlineHTML: true,
|
|
103
|
+
srcUrl: ''
|
|
104
|
+
},
|
|
105
|
+
visual: {
|
|
106
|
+
border: false,
|
|
107
|
+
accent: false,
|
|
108
|
+
background: false,
|
|
109
|
+
hideBackgroundColor: false,
|
|
110
|
+
borderColorTheme: false
|
|
111
|
+
}
|
|
112
|
+
}}
|
|
113
|
+
datasets={{}}
|
|
114
|
+
isDashboard={true}
|
|
115
|
+
/>
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
await waitFor(() => expect(container.querySelector('.markup-include-content-container')).toBeInTheDocument())
|
|
119
|
+
|
|
120
|
+
expect(container.querySelector('.cove-visualization__filters-section')).not.toBeInTheDocument()
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('keeps included bootstrap column markup inside the shared content section', async () => {
|
|
124
|
+
const { container } = render(
|
|
125
|
+
<CdcMarkupInclude
|
|
126
|
+
config={{
|
|
127
|
+
type: 'markup-include',
|
|
128
|
+
theme: 'theme-blue',
|
|
129
|
+
markupVariables: [],
|
|
130
|
+
contentEditor: {
|
|
131
|
+
title: 'Grid mock',
|
|
132
|
+
inlineHTML: `
|
|
133
|
+
<div class="row">
|
|
134
|
+
<div class="col-8"><p>Primary content</p></div>
|
|
135
|
+
<div class="col-3"><p>Secondary content</p></div>
|
|
136
|
+
</div>
|
|
137
|
+
`,
|
|
138
|
+
useInlineHTML: true,
|
|
139
|
+
srcUrl: ''
|
|
140
|
+
},
|
|
141
|
+
visual: {
|
|
142
|
+
border: false,
|
|
143
|
+
accent: false,
|
|
144
|
+
background: false,
|
|
145
|
+
hideBackgroundColor: false,
|
|
146
|
+
borderColorTheme: false
|
|
147
|
+
}
|
|
148
|
+
}}
|
|
149
|
+
datasets={{}}
|
|
150
|
+
isDashboard={true}
|
|
151
|
+
/>
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
await waitFor(() => expect(container.querySelector('.markup-include-content-container')).toBeInTheDocument())
|
|
155
|
+
|
|
156
|
+
const shell = container.querySelector('.cove-visualization.type-markup-include')
|
|
157
|
+
const contentSection = container.querySelector('.cove-visualization__content-section')
|
|
158
|
+
const primaryColumn = container.querySelector('.col-8')
|
|
159
|
+
const secondaryColumn = container.querySelector('.col-3')
|
|
160
|
+
|
|
161
|
+
expect(shell).toBeInTheDocument()
|
|
162
|
+
expect(contentSection).toBeInTheDocument()
|
|
163
|
+
expect(primaryColumn).toBeInTheDocument()
|
|
164
|
+
expect(secondaryColumn).toBeInTheDocument()
|
|
165
|
+
expect(primaryColumn?.closest('.cove-visualization__content-section')).toBe(contentSection)
|
|
166
|
+
expect(secondaryColumn?.closest('.cove-visualization__content-section')).toBe(contentSection)
|
|
167
|
+
expect(primaryColumn?.parentElement).not.toBe(shell)
|
|
168
|
+
expect(secondaryColumn?.parentElement).not.toBe(shell)
|
|
69
169
|
})
|
|
70
170
|
|
|
71
171
|
it('keeps the minimal example in sync with the README docs', () => {
|