@cdc/markup-include 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/LICENSE +201 -0
- package/dist/cdcmarkupinclude.js +11506 -11344
- package/examples/default.json +69 -0
- package/index.html +1 -29
- package/package.json +32 -35
- package/src/CdcMarkupInclude.tsx +73 -110
- package/src/_stories/MarkupInclude.Editor.stories.tsx +11 -16
- package/src/cdcMarkupInclude.style.css +15 -11
- package/src/components/EditorPanel/EditorPanel.styles.css +1 -1
- package/src/components/EditorPanel/EditorPanel.tsx +60 -4
- package/src/data/initial-state.js +4 -2
- package/src/scss/main.scss +17 -13
- package/src/test/CdcMarkupInclude.test.jsx +2 -2
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contentEditor": {
|
|
3
|
+
"inlineHTML": "<div>The age adjusted rate for {{race}} was 644.2, compared to Non-Hispanic American Indian, which was {{ageAdjustedRate}}.</div>",
|
|
4
|
+
"markupVariables": [
|
|
5
|
+
{
|
|
6
|
+
"name": "race",
|
|
7
|
+
"tag": "{{race}}",
|
|
8
|
+
"columnName": "Race",
|
|
9
|
+
"conditions": [
|
|
10
|
+
{
|
|
11
|
+
"columnName": "Age-adjusted rate",
|
|
12
|
+
"isOrIsNotEqualTo": "is",
|
|
13
|
+
"value": "644.2"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "ageAdjustedRate",
|
|
19
|
+
"tag": "{{ageAdjustedRate}}",
|
|
20
|
+
"columnName": "Age-adjusted rate",
|
|
21
|
+
"conditions": [
|
|
22
|
+
{
|
|
23
|
+
"columnName": "Race",
|
|
24
|
+
"isOrIsNotEqualTo": "is",
|
|
25
|
+
"value": "Non-Hispanic American Indian"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"showHeader": false,
|
|
31
|
+
"srcUrl": "https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/examples/Markup-Include-Button-and-Text.html",
|
|
32
|
+
"title": "",
|
|
33
|
+
"useInlineHTML": false
|
|
34
|
+
},
|
|
35
|
+
"data": [
|
|
36
|
+
{
|
|
37
|
+
"Race": "Hispanic or Latino",
|
|
38
|
+
"Age-adjusted rate": "644.2"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"Race": "Non-Hispanic American Indian",
|
|
42
|
+
"Age-adjusted rate": "636.1"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"Race": "Non-Hispanic Black",
|
|
46
|
+
"Age-adjusted rate": "563.7"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"Race": "Non-Hispanic Asian or Pacific Islander",
|
|
50
|
+
"Age-adjusted rate": "202.5"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"Race": "Non-Hispanic White",
|
|
54
|
+
"Age-adjusted rate": "183.6"
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"legend": {},
|
|
58
|
+
"newViz": true,
|
|
59
|
+
"theme": "theme-amber",
|
|
60
|
+
"type": "markup-include",
|
|
61
|
+
"runtime": null,
|
|
62
|
+
"visual": {
|
|
63
|
+
"border": false,
|
|
64
|
+
"accent": true,
|
|
65
|
+
"background": true,
|
|
66
|
+
"hideBackgroundColor": false,
|
|
67
|
+
"borderColorTheme": false
|
|
68
|
+
}
|
|
69
|
+
}
|
package/index.html
CHANGED
|
@@ -1,29 +1 @@
|
|
|
1
|
-
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
|
6
|
-
<style type="text/css">
|
|
7
|
-
body {
|
|
8
|
-
margin: 0;
|
|
9
|
-
border-top: none !important;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/* Add 1rem padding to mimic DFE when editor is not visible */
|
|
13
|
-
.cdc-open-viz-module:not(.isEditor) {
|
|
14
|
-
padding: 1rem;
|
|
15
|
-
}
|
|
16
|
-
</style>
|
|
17
|
-
<link rel="stylesheet prefetch" href="https://www.cdc.gov/TemplatePackage/5.0/css/app.min.css?_=71669" />
|
|
18
|
-
</head>
|
|
19
|
-
|
|
20
|
-
<body>
|
|
21
|
-
<!-- Original -->
|
|
22
|
-
|
|
23
|
-
<!-- DATA PRESENTATION GALLERY: https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/Markup-Include.html#examples -->
|
|
24
|
-
<!-- <div class="react-container" data-config="/src/_stories/_mock/icon-no-text.json"></div> -->
|
|
25
|
-
<!-- <div class="react-container" data-config="/src/_stories/_mock/image-with-text.json"></div> -->
|
|
26
|
-
<div class="react-container" data-config="/src/_stories/_mock/button-and-text.json"></div>
|
|
27
|
-
<script type="module" src="./src/index.tsx"></script>
|
|
28
|
-
</body>
|
|
29
|
-
</html>
|
|
1
|
+
<!-- index.html is generated by @cdc/core/generateViteConfig.js using the files in @cdc/core/devTemplate/ -->
|
package/package.json
CHANGED
|
@@ -1,49 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/markup-include",
|
|
3
|
-
"version": "4.26.
|
|
3
|
+
"version": "4.26.3",
|
|
4
4
|
"description": "React component for displaying HTML content from an outside link",
|
|
5
|
-
"moduleName": "CdcMarkupInclude",
|
|
6
|
-
"main": "dist/cdcmarkupinclude",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"scripts": {
|
|
9
|
-
"start": "vite --open",
|
|
10
|
-
"build": "vite build",
|
|
11
|
-
"preview": "vite preview",
|
|
12
|
-
"graph": "nx graph",
|
|
13
|
-
"prepublishOnly": "lerna run --scope @cdc/markup-include build",
|
|
14
|
-
"test": "vitest run --reporter verbose",
|
|
15
|
-
"test-watch": "vitest watch --reporter verbose",
|
|
16
|
-
"test-watch:ui": "vitest --ui"
|
|
17
|
-
},
|
|
18
|
-
"repository": {
|
|
19
|
-
"type": "git",
|
|
20
|
-
"url": "git+https://github.com/CDCgov/cdc-open-viz",
|
|
21
|
-
"directory": "packages/markup-include"
|
|
22
|
-
},
|
|
23
|
-
"author": "Rob Shelnutt <rob@blackairplane.com>",
|
|
24
|
-
"bugs": {
|
|
25
|
-
"url": "https://github.com/CDCgov/cdc-open-viz/issues"
|
|
26
|
-
},
|
|
27
5
|
"license": "Apache-2.0",
|
|
28
|
-
"
|
|
6
|
+
"author": "Rob Shelnutt <rob@blackairplane.com>",
|
|
7
|
+
"bugs": "https://github.com/CDCgov/cdc-open-viz/issues",
|
|
29
8
|
"dependencies": {
|
|
30
|
-
"@cdc/core": "^4.26.
|
|
31
|
-
"axios": "^1.
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"lodash": "^4.17.21",
|
|
9
|
+
"@cdc/core": "^4.26.3",
|
|
10
|
+
"axios": "^1.13.2",
|
|
11
|
+
"dompurify": "^3.3.1",
|
|
12
|
+
"lodash": "^4.17.23",
|
|
35
13
|
"react-accessible-accordion": "^5.0.1"
|
|
36
14
|
},
|
|
37
|
-
"peerDependencies": {
|
|
38
|
-
"react": "^18.2.0",
|
|
39
|
-
"react-dom": "^18.2.0"
|
|
40
|
-
},
|
|
41
15
|
"devDependencies": {
|
|
42
16
|
"@rollup/plugin-dsv": "^3.0.2",
|
|
43
|
-
"@vitejs/plugin-react": "^
|
|
17
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
44
18
|
"sass": "^1.89.2",
|
|
45
19
|
"vite-plugin-css-injected-by-js": "^2.4.0",
|
|
46
20
|
"vite-plugin-svgr": "^4.2.0"
|
|
47
21
|
},
|
|
48
|
-
"gitHead": "
|
|
22
|
+
"gitHead": "d50e45a074fbefa56cac904917e707d57f237737",
|
|
23
|
+
"homepage": "https://github.com/CDCgov/cdc-open-viz#readme",
|
|
24
|
+
"main": "dist/cdcmarkupinclude",
|
|
25
|
+
"moduleName": "CdcMarkupInclude",
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"react": "^18.2.0",
|
|
28
|
+
"react-dom": "^18.2.0"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/CDCgov/cdc-open-viz",
|
|
33
|
+
"directory": "packages/markup-include"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "vite build",
|
|
37
|
+
"graph": "nx graph",
|
|
38
|
+
"prepublishOnly": "lerna run --scope @cdc/markup-include build",
|
|
39
|
+
"preview": "vite preview",
|
|
40
|
+
"start": "vite --open",
|
|
41
|
+
"test": "vitest run --reporter verbose",
|
|
42
|
+
"test-watch": "vitest watch --reporter verbose",
|
|
43
|
+
"test-watch:ui": "vitest --ui"
|
|
44
|
+
},
|
|
45
|
+
"type": "module"
|
|
49
46
|
}
|
package/src/CdcMarkupInclude.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useEffect, useCallback, useRef, useReducer, useMemo } from 'react'
|
|
2
|
-
import _ from 'lodash'
|
|
3
2
|
// external
|
|
4
|
-
import
|
|
3
|
+
import DOMPurify from 'dompurify'
|
|
5
4
|
import axios from 'axios'
|
|
6
5
|
|
|
7
6
|
// cdc
|
|
@@ -11,6 +10,7 @@ import { processMarkupVariables } from '@cdc/core/helpers/markupProcessor'
|
|
|
11
10
|
import { addValuesToFilters } from '@cdc/core/helpers/addValuesToFilters'
|
|
12
11
|
import ConfigContext from './ConfigContext'
|
|
13
12
|
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
13
|
+
import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData'
|
|
14
14
|
import EditorPanel from '../src/components/EditorPanel'
|
|
15
15
|
import defaults from './data/initial-state'
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ import Loading from '@cdc/core/components/Loading'
|
|
|
19
19
|
import Filters from '@cdc/core/components/Filters'
|
|
20
20
|
import useDataVizClasses from '@cdc/core/helpers/useDataVizClasses'
|
|
21
21
|
import markupIncludeReducer from './store/markupInclude.reducer'
|
|
22
|
-
import
|
|
22
|
+
import { VisualizationContainer, VisualizationContent } from '@cdc/core/components/Layout'
|
|
23
23
|
// styles
|
|
24
24
|
import './cdcMarkupInclude.style.css'
|
|
25
25
|
import './scss/main.scss'
|
|
@@ -79,10 +79,6 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
79
79
|
|
|
80
80
|
const { inlineHTML, srcUrl, title, useInlineHTML } = contentEditor || {}
|
|
81
81
|
|
|
82
|
-
const shouldApplyTopPadding =
|
|
83
|
-
visual?.border || visual?.background || (contentEditor?.title && contentEditor?.titleStyle === 'legacy')
|
|
84
|
-
const shouldApplySidePadding = visual?.border || visual?.accent || visual?.background
|
|
85
|
-
|
|
86
82
|
// Default Functions
|
|
87
83
|
const updateConfig = newConfig => {
|
|
88
84
|
Object.keys(defaults).forEach(key => {
|
|
@@ -112,8 +108,9 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
112
108
|
let responseData = response.data ?? {}
|
|
113
109
|
|
|
114
110
|
if (response.dataUrl) {
|
|
115
|
-
const
|
|
116
|
-
responseData =
|
|
111
|
+
const { data, dataMetadata } = await fetchRemoteData(response.dataUrl)
|
|
112
|
+
responseData = data
|
|
113
|
+
response.dataMetadata = dataMetadata
|
|
117
114
|
}
|
|
118
115
|
|
|
119
116
|
response.data = responseData
|
|
@@ -124,7 +121,7 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
124
121
|
processedConfig.filters = addValuesToFilters(processedConfig.filters, responseData)
|
|
125
122
|
}
|
|
126
123
|
|
|
127
|
-
updateConfig({ ...
|
|
124
|
+
updateConfig({ ...defaults, ...processedConfig })
|
|
128
125
|
dispatch({ type: 'SET_LOADING', payload: false })
|
|
129
126
|
}
|
|
130
127
|
|
|
@@ -203,63 +200,29 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
203
200
|
}
|
|
204
201
|
|
|
205
202
|
/**
|
|
206
|
-
*
|
|
207
|
-
* This ensures that the CSS is applied only to this COVE visualization.
|
|
203
|
+
* Extracts <style> tags from HTML and scopes them using CSS nesting under the given scope ID.
|
|
208
204
|
*/
|
|
209
|
-
const
|
|
210
|
-
if (!html || typeof html !== 'string') return html
|
|
205
|
+
const extractAndScopeStyles = (html: string, scopeId: string): { scopedCSS: string; cleanHTML: string } => {
|
|
206
|
+
if (!html || typeof html !== 'string') return { scopedCSS: '', cleanHTML: html }
|
|
211
207
|
|
|
212
|
-
// Use DOMParser to parse HTML
|
|
213
208
|
const parser = new DOMParser()
|
|
214
209
|
const doc = parser.parseFromString(html, 'text/html')
|
|
215
210
|
|
|
216
|
-
// Extract all <style> elements
|
|
217
211
|
const styleElements = doc.querySelectorAll('style')
|
|
218
|
-
if (styleElements.length === 0) return html
|
|
219
|
-
|
|
220
|
-
// Parse CSS rules
|
|
221
|
-
const sheet = new CSSStyleSheet()
|
|
222
|
-
const cssRules: Array<{ selector: string; styles: string }> = []
|
|
212
|
+
if (styleElements.length === 0) return { scopedCSS: '', cleanHTML: html }
|
|
223
213
|
|
|
214
|
+
const cssFragments: string[] = []
|
|
224
215
|
styleElements.forEach(styleEl => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
// Extract parsed rules from the stylesheet
|
|
230
|
-
for (let i = 0; i < sheet.cssRules.length; i++) {
|
|
231
|
-
const rule = sheet.cssRules[i]
|
|
232
|
-
if (rule instanceof CSSStyleRule) {
|
|
233
|
-
cssRules.push({
|
|
234
|
-
selector: rule.selectorText,
|
|
235
|
-
styles: rule.style.cssText
|
|
236
|
-
})
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
} catch (e) {
|
|
240
|
-
console.warn('Markup Include: Invalid CSS in style tag', e)
|
|
216
|
+
const text = styleEl.textContent?.trim()
|
|
217
|
+
if (text) {
|
|
218
|
+
cssFragments.push(text)
|
|
241
219
|
}
|
|
242
|
-
|
|
243
220
|
styleEl.remove()
|
|
244
221
|
})
|
|
245
222
|
|
|
246
|
-
|
|
247
|
-
for (const rule of cssRules) {
|
|
248
|
-
try {
|
|
249
|
-
const elements = doc.body.querySelectorAll(rule.selector)
|
|
250
|
-
|
|
251
|
-
elements.forEach(el => {
|
|
252
|
-
const existingStyle = el.getAttribute('style') || ''
|
|
253
|
-
const newStyle = existingStyle ? `${existingStyle}; ${rule.styles}` : rule.styles
|
|
254
|
-
el.setAttribute('style', newStyle)
|
|
255
|
-
})
|
|
256
|
-
} catch (e) {
|
|
257
|
-
// Skip invalid selectors (e.g., pseudo-selectors like :hover won't match)
|
|
258
|
-
console.warn(`Markup Include: Could not apply CSS rule for selector "${rule.selector}"`, e)
|
|
259
|
-
}
|
|
260
|
-
}
|
|
223
|
+
const scopedCSS = cssFragments.length > 0 ? `#${scopeId} {\n${cssFragments.join('\n')}\n}` : ''
|
|
261
224
|
|
|
262
|
-
return doc.body.innerHTML
|
|
225
|
+
return { scopedCSS, cleanHTML: doc.body.innerHTML }
|
|
263
226
|
}
|
|
264
227
|
|
|
265
228
|
//Load initial config
|
|
@@ -289,69 +252,69 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
289
252
|
allowHideSection,
|
|
290
253
|
filters: config?.filters || [],
|
|
291
254
|
datasets,
|
|
292
|
-
configDataKey: config?.dataKey
|
|
255
|
+
configDataKey: config?.dataKey,
|
|
256
|
+
locale: config?.locale,
|
|
257
|
+
dataMetadata: config?.dataMetadata
|
|
293
258
|
})
|
|
294
259
|
: { processedContent: parseBodyMarkup(urlMarkup), shouldHideSection: false, shouldShowNoDataMessage: false }
|
|
295
260
|
|
|
296
|
-
const
|
|
261
|
+
const scopeId = `cove-mi-${config?.runtime?.uniqueId || 'default'}`
|
|
262
|
+
const { scopedCSS, cleanHTML } = extractAndScopeStyles(processedMarkup.processedContent, scopeId)
|
|
263
|
+
const sanitizedHTML = cleanHTML ? DOMPurify.sanitize(cleanHTML) : ''
|
|
297
264
|
|
|
298
265
|
const hideMarkupInclude = processedMarkup.shouldHideSection
|
|
299
266
|
const _showNoDataMessage = processedMarkup.shouldShowNoDataMessage
|
|
300
267
|
|
|
301
268
|
if (loading === false) {
|
|
302
|
-
content = (
|
|
303
|
-
|
|
304
|
-
{
|
|
305
|
-
|
|
306
|
-
{
|
|
307
|
-
|
|
308
|
-
<
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
enableMarkupVariables={config?.enableMarkupVariables}
|
|
349
|
-
data={data}
|
|
350
|
-
/>
|
|
351
|
-
</div>
|
|
352
|
-
</Layout.Responsive>
|
|
269
|
+
content = !hideMarkupInclude && (
|
|
270
|
+
<VisualizationContent
|
|
271
|
+
innerClassName={`markup-include-content-container ${innerContainerClasses.join(' ')}`.trim()}
|
|
272
|
+
bodyClassName={`markup-include-component ${contentClasses.join(' ')}`.trim()}
|
|
273
|
+
message={
|
|
274
|
+
config.filters && config.filters.length > 0 ? (
|
|
275
|
+
<Filters
|
|
276
|
+
config={config}
|
|
277
|
+
setFilters={setFilters}
|
|
278
|
+
excludedData={data || []}
|
|
279
|
+
dimensions={[0, 0]}
|
|
280
|
+
interactionLabel={interactionLabel || 'markup-include'}
|
|
281
|
+
/>
|
|
282
|
+
) : null
|
|
283
|
+
}
|
|
284
|
+
header={
|
|
285
|
+
<Title
|
|
286
|
+
title={title}
|
|
287
|
+
isDashboard={isDashboard}
|
|
288
|
+
titleStyle={contentEditor?.titleStyle}
|
|
289
|
+
config={config}
|
|
290
|
+
classes={[`${theme}`, 'mb-0']}
|
|
291
|
+
noContent={!sanitizedHTML}
|
|
292
|
+
/>
|
|
293
|
+
}
|
|
294
|
+
footer={
|
|
295
|
+
<FootnotesStandAlone
|
|
296
|
+
config={configObj?.footnotes}
|
|
297
|
+
filters={config?.filters || []}
|
|
298
|
+
markupVariables={markupVariables}
|
|
299
|
+
enableMarkupVariables={config?.enableMarkupVariables}
|
|
300
|
+
data={data}
|
|
301
|
+
dataMetadata={config?.dataMetadata}
|
|
302
|
+
/>
|
|
303
|
+
}
|
|
304
|
+
>
|
|
305
|
+
{_showNoDataMessage && (
|
|
306
|
+
<div className='no-data-message'>
|
|
307
|
+
<p>{`${noDataMessageText}`}</p>
|
|
308
|
+
</div>
|
|
309
|
+
)}
|
|
310
|
+
{!markupError && !_showNoDataMessage && (
|
|
311
|
+
<div id={scopeId}>
|
|
312
|
+
{scopedCSS && <style>{scopedCSS}</style>}
|
|
313
|
+
<div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />
|
|
314
|
+
</div>
|
|
353
315
|
)}
|
|
354
|
-
|
|
316
|
+
{markupError && srcUrl && !_showNoDataMessage && <div className='warning'>{errorMessage}</div>}
|
|
317
|
+
</VisualizationContent>
|
|
355
318
|
)
|
|
356
319
|
}
|
|
357
320
|
|
|
@@ -370,9 +333,9 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
|
|
|
370
333
|
<ErrorBoundary component='CdcMarkupInclude'>
|
|
371
334
|
<ConfigContext.Provider value={{ config, updateConfig, loading, data: data, setParentConfig, isDashboard }}>
|
|
372
335
|
{!config?.newViz && config?.runtime && config?.runtime.editorErrorMessage && <Error />}
|
|
373
|
-
<
|
|
336
|
+
<VisualizationContainer config={config} isEditor={isEditor} editorPanel={<EditorPanel datasets={datasets} />}>
|
|
374
337
|
{content}
|
|
375
|
-
</
|
|
338
|
+
</VisualizationContainer>
|
|
376
339
|
</ConfigContext.Provider>
|
|
377
340
|
</ErrorBoundary>
|
|
378
341
|
)
|
|
@@ -138,7 +138,7 @@ export const GeneralSectionTests: Story = {
|
|
|
138
138
|
'Title Update',
|
|
139
139
|
() => {
|
|
140
140
|
const modernTitle = canvasElement.querySelector('.cove-title')
|
|
141
|
-
const legacyTitle = canvasElement.querySelector('.cove-
|
|
141
|
+
const legacyTitle = canvasElement.querySelector('.cove-visualization__header h2')
|
|
142
142
|
const titleElement = modernTitle || legacyTitle
|
|
143
143
|
return titleElement?.textContent?.trim() || ''
|
|
144
144
|
},
|
|
@@ -150,7 +150,7 @@ export const GeneralSectionTests: Story = {
|
|
|
150
150
|
)
|
|
151
151
|
|
|
152
152
|
const modernHeader = canvasElement.querySelector('.cove-title')
|
|
153
|
-
const legacyHeader = canvasElement.querySelector('.cove-
|
|
153
|
+
const legacyHeader = canvasElement.querySelector('.cove-visualization__header h2')
|
|
154
154
|
const headerElement = modernHeader || legacyHeader
|
|
155
155
|
expect(headerElement).toBeTruthy()
|
|
156
156
|
expect(headerElement!.textContent?.trim()).toBe('Updated Markup Include Title E2E')
|
|
@@ -226,7 +226,7 @@ export const ContentEditorTests: Story = {
|
|
|
226
226
|
await performAndAssert(
|
|
227
227
|
'HTML Content Update',
|
|
228
228
|
() => {
|
|
229
|
-
const contentElement = canvasElement.querySelector('.cove-
|
|
229
|
+
const contentElement = canvasElement.querySelector('.cove-visualization__body')
|
|
230
230
|
return contentElement?.innerHTML || ''
|
|
231
231
|
},
|
|
232
232
|
async () => {
|
|
@@ -255,7 +255,7 @@ export const ContentEditorTests: Story = {
|
|
|
255
255
|
'Source URL Update and Content Loading',
|
|
256
256
|
() => ({
|
|
257
257
|
inputValue: srcUrlInput.value,
|
|
258
|
-
contentText: canvasElement.querySelector('.cove-
|
|
258
|
+
contentText: canvasElement.querySelector('.cove-visualization__body')?.textContent || ''
|
|
259
259
|
}),
|
|
260
260
|
async () => {
|
|
261
261
|
await userEvent.clear(srcUrlInput)
|
|
@@ -296,7 +296,7 @@ export const VisualSectionTests: Story = {
|
|
|
296
296
|
await waitForEditor(canvas)
|
|
297
297
|
await openAccordion(canvas, 'Visual')
|
|
298
298
|
|
|
299
|
-
const contentContainer = () => canvasElement.querySelector('.cove-
|
|
299
|
+
const contentContainer = () => canvasElement.querySelector('.cove-visualization__body') as HTMLElement
|
|
300
300
|
const visualContainer = () => canvasElement.querySelector('.markup-include-component') as HTMLElement
|
|
301
301
|
expect(contentContainer()).toBeTruthy()
|
|
302
302
|
expect(visualContainer()).toBeTruthy()
|
|
@@ -306,21 +306,16 @@ export const VisualSectionTests: Story = {
|
|
|
306
306
|
// Expectation: Theme class changes on component
|
|
307
307
|
// ============================================================================
|
|
308
308
|
const getThemeState = () => {
|
|
309
|
-
// Use the contentContainer like other tests, and check its parent for theme classes
|
|
310
309
|
const content = contentContainer()
|
|
311
310
|
if (!content) return { theme: '', classes: '', element: 'content not found' }
|
|
312
311
|
|
|
313
|
-
//
|
|
312
|
+
// Theme is applied to the outer cove-visualization wrapper — traverse up to find it
|
|
313
|
+
const themeWrapper = content.closest('[class*="theme-"]') as HTMLElement
|
|
314
|
+
const theme = themeWrapper ? Array.from(themeWrapper.classList).find(cls => cls.startsWith('theme-')) || '' : ''
|
|
315
|
+
|
|
314
316
|
const contentClasses = Array.from(content.classList).join(' ')
|
|
315
317
|
const parentClasses = content.parentElement ? Array.from(content.parentElement.classList).join(' ') : ''
|
|
316
318
|
|
|
317
|
-
const contentTheme = Array.from(content.classList).find(cls => cls.startsWith('theme-')) || ''
|
|
318
|
-
const parentTheme = content.parentElement
|
|
319
|
-
? Array.from(content.parentElement.classList).find(cls => cls.startsWith('theme-')) || ''
|
|
320
|
-
: ''
|
|
321
|
-
|
|
322
|
-
const theme = contentTheme || parentTheme || ''
|
|
323
|
-
|
|
324
319
|
return {
|
|
325
320
|
theme,
|
|
326
321
|
classes: contentClasses + ' | parent: ' + parentClasses,
|
|
@@ -380,7 +375,7 @@ export const VisualSectionTests: Story = {
|
|
|
380
375
|
'Border Color Theme Toggle',
|
|
381
376
|
() => ({
|
|
382
377
|
checked: borderColorThemeCheckbox.checked,
|
|
383
|
-
hasBorderColorTheme: visualContainer().classList.contains('component--has-
|
|
378
|
+
hasBorderColorTheme: visualContainer().classList.contains('component--has-border-color-theme')
|
|
384
379
|
}),
|
|
385
380
|
async () => {
|
|
386
381
|
const checkboxWrapper =
|
|
@@ -455,7 +450,7 @@ export const VisualSectionTests: Story = {
|
|
|
455
450
|
'Hide Background Color Toggle',
|
|
456
451
|
() => ({
|
|
457
452
|
checked: hideBackgroundCheckbox.checked,
|
|
458
|
-
hideBackground: visualContainer().classList.contains('component--
|
|
453
|
+
hideBackground: visualContainer().classList.contains('component--hide-background-color')
|
|
459
454
|
}),
|
|
460
455
|
async () => {
|
|
461
456
|
const checkboxWrapper = hideBackgroundCheckbox.closest('.cove-input__checkbox--small') || hideBackgroundCheckbox
|
|
@@ -1,39 +1,43 @@
|
|
|
1
|
-
.
|
|
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-
|
|
10
|
-
.markup-include-component.cove-
|
|
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
|
-
.
|
|
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
|
-
|
|
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
|
+
}
|