@cdc/markup-include 4.24.9 → 4.24.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/markup-include",
3
- "version": "4.24.9",
3
+ "version": "4.24.11",
4
4
  "description": "React component for displaying HTML content from an outside link",
5
5
  "moduleName": "CdcMarkupInclude",
6
6
  "main": "dist/cdcmarkupinclude",
@@ -27,7 +27,7 @@
27
27
  "license": "Apache-2.0",
28
28
  "homepage": "https://github.com/CDCgov/cdc-open-viz#readme",
29
29
  "dependencies": {
30
- "@cdc/core": "^4.24.9",
30
+ "@cdc/core": "^4.24.11",
31
31
  "axios": "^1.6.0",
32
32
  "chroma": "0.0.1",
33
33
  "chroma-js": "^2.1.0",
@@ -39,5 +39,5 @@
39
39
  "react": "^18.2.0",
40
40
  "react-dom": "^18.2.0"
41
41
  },
42
- "gitHead": "c4b0402afe6ed209a85b7078711549b9fd7dae7d"
42
+ "gitHead": "9ab5ee9b2b0ef7321a66a2104be6ce8899ec3808"
43
43
  }
@@ -1,4 +1,4 @@
1
- import { useEffect, useCallback, useRef, useReducer, useState } from 'react'
1
+ import { useEffect, useCallback, useRef, useReducer, useMemo } from 'react'
2
2
  import _ from 'lodash'
3
3
  // external
4
4
  import { Markup } from 'interweave'
@@ -31,8 +31,21 @@ type CdcMarkupIncludeProps = {
31
31
 
32
32
  import Title from '@cdc/core/components/ui/Title'
33
33
 
34
- const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({ configUrl, config: configObj, isDashboard = true, isEditor = false, setConfig: setParentConfig }) => {
35
- const initialState = { config: configObj, loading: true, urlMarkup: '', markupError: null, errorMessage: null, coveLoadedHasRan: false }
34
+ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({
35
+ configUrl,
36
+ config: configObj,
37
+ isDashboard = true,
38
+ isEditor = false,
39
+ setConfig: setParentConfig
40
+ }) => {
41
+ const initialState = {
42
+ config: configObj,
43
+ loading: true,
44
+ urlMarkup: '',
45
+ markupError: null,
46
+ errorMessage: null,
47
+ coveLoadedHasRan: false
48
+ }
36
49
 
37
50
  const [state, dispatch] = useReducer(markupIncludeReducer, initialState)
38
51
 
@@ -92,7 +105,8 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({ configUrl, config:
92
105
  let errorList = {
93
106
  200: 'This is likely due to a CORS restriction policy from the remote origin address.',
94
107
  404: 'The requested source URL cannot be found. Please verify the link address provided.',
95
- proto: 'Provided source URL must include https:// or http:// before the address (depending on the source content type).'
108
+ proto:
109
+ 'Provided source URL must include https:// or http:// before the address (depending on the source content type).'
96
110
  }
97
111
 
98
112
  message += errorList[errorCode]
@@ -138,46 +152,58 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({ configUrl, config:
138
152
  const filterOutConditions = (workingData, conditionList) => {
139
153
  const { columnName, isOrIsNotEqualTo, value } = conditionList[0]
140
154
 
141
- const newWorkingData = isOrIsNotEqualTo === 'is' ? workingData.filter(dataObject => dataObject[columnName] === value) : workingData.filter(dataObject => dataObject[columnName] !== value)
155
+ const newWorkingData =
156
+ isOrIsNotEqualTo === 'is'
157
+ ? workingData?.filter(dataObject => dataObject[columnName] === value)
158
+ : workingData?.filter(dataObject => dataObject[columnName] !== value)
142
159
 
143
160
  conditionList.shift()
144
161
  return conditionList.length === 0 ? newWorkingData : filterOutConditions(newWorkingData, conditionList)
145
162
  }
146
163
 
164
+ const emptyVariableChecker = []
165
+
147
166
  const convertVariablesInMarkup = inlineMarkup => {
148
167
  if (_.isEmpty(markupVariables)) return inlineMarkup
149
168
  const variableRegexPattern = /{{(.*?)}}/g
150
169
  const convertedInlineMarkup = inlineMarkup.replace(variableRegexPattern, variableTag => {
170
+ if (emptyVariableChecker.length > 0) return
151
171
  const workingVariable = markupVariables.filter(variable => variable.tag === variableTag)[0]
152
172
  if (workingVariable === undefined) return [variableTag]
153
- const workingData = workingVariable && workingVariable.conditions.length === 0 ? data : filterOutConditions(data, [...workingVariable.conditions])
173
+ const workingData =
174
+ workingVariable && workingVariable.conditions.length === 0
175
+ ? data
176
+ : filterOutConditions(data, [...workingVariable.conditions])
177
+
178
+ const variableValues: string[] = _.uniq(
179
+ (workingData || []).map(dataObject => {
180
+ const dataObjectValue = dataObject[workingVariable.columnName]
181
+ return workingVariable.addCommas && !isNaN(parseFloat(dataObjectValue))
182
+ ? parseFloat(dataObjectValue).toLocaleString('en-US', { useGrouping: true })
183
+ : dataObjectValue
184
+ })
185
+ )
154
186
 
155
- const variableValues: string[] = _.uniq(workingData?.map(dataObject => dataObject[workingVariable.columnName]))
156
187
  const variableDisplay = []
157
188
 
158
189
  const listConjunction = !isEditor ? 'and' : 'or'
159
190
 
160
191
  const length = variableValues.length
161
192
  if (length === 2) {
162
- variableValues.push(variableValues.join(` ${listConjunction} `))
193
+ const newVariableValues = variableValues.join(` ${listConjunction} `)
194
+ variableValues.splice(0, 2, newVariableValues)
163
195
  }
164
196
  if (length > 2) {
165
197
  variableValues[length - 1] = `${listConjunction} ${variableValues[length - 1]}`
166
198
  }
167
199
  variableDisplay.push(variableValues.join(', '))
168
200
 
169
- let finalDisplay = variableDisplay[0]
201
+ const finalDisplay = variableDisplay[0]
170
202
 
171
- if(workingVariable.addCommas && !isNaN(parseFloat(finalDisplay))){
172
- finalDisplay = parseFloat(finalDisplay)
173
- finalDisplay = finalDisplay.toLocaleString('en-US', {useGrouping: true})
203
+ if (finalDisplay === '' && contentEditor.allowHideSection) {
204
+ emptyVariableChecker.push(true)
174
205
  }
175
-
176
- const displayInfoMessage = '<span class="font-weight-bold display-Info-message">One or more of the following values will appear in the place of this variable placeholder:</span>'
177
-
178
- const newReplacementForVariable = `<span class="cove-tooltip-variable">${variableTag}<span class="cove-tooltip-value">${displayInfoMessage}<br/>${finalDisplay}</span></span><span class="cove-markup-include-variable-value">${finalDisplay}</span>`
179
-
180
- return newReplacementForVariable
206
+ return finalDisplay
181
207
  })
182
208
  return convertedInlineMarkup
183
209
  }
@@ -210,11 +236,6 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({ configUrl, config:
210
236
  }
211
237
  }, [config, container])
212
238
 
213
- //Reload config if config object provided/updated
214
- useEffect(() => {
215
- loadConfig().catch(err => console.log(err))
216
- }, [configObj?.data])
217
-
218
239
  //Reload any functions when config is updated
219
240
  useEffect(() => {
220
241
  loadConfigMarkupData().catch(err => console.log(err))
@@ -224,23 +245,27 @@ const CdcMarkupInclude: React.FC<CdcMarkupIncludeProps> = ({ configUrl, config:
224
245
 
225
246
  const markup = useInlineHTML ? convertVariablesInMarkup(inlineHTML) : parseBodyMarkup(urlMarkup)
226
247
 
248
+ const hideMarkupInclude = contentEditor?.allowHideSection && emptyVariableChecker.length > 0 && !isEditor
249
+
227
250
  if (loading === false) {
228
251
  content = (
229
252
  <>
230
253
  {isEditor && <EditorPanel />}
231
- <Layout.Responsive isEditor={isEditor}>
232
- <div className='markup-include-content-container cove-component__content no-borders'>
233
- <div className={`markup-include-component ${contentClasses.join(' ')}`}>
234
- <Title title={title} isDashboard={isDashboard} classes={[`${theme}`, 'mb-0']} />
235
- <div className={`${innerContainerClasses.join(' ')}`}>
236
- <div className='cove-component__content-wrap'>
237
- {!markupError && <Markup allowElements={!!urlMarkup} content={markup} />}
238
- {markupError && srcUrl && <div className='warning'>{errorMessage}</div>}
254
+ {!hideMarkupInclude && (
255
+ <Layout.Responsive isEditor={isEditor}>
256
+ <div className='markup-include-content-container cove-component__content no-borders'>
257
+ <div className={`markup-include-component ${contentClasses.join(' ')}`}>
258
+ <Title title={title} isDashboard={isDashboard} classes={[`${theme}`, 'mb-0']} />
259
+ <div className={`${innerContainerClasses.join(' ')}`}>
260
+ <div className='cove-component__content-wrap'>
261
+ {!markupError && <Markup allowElements={!!urlMarkup} content={markup} />}
262
+ {markupError && srcUrl && <div className='warning'>{errorMessage}</div>}
263
+ </div>
239
264
  </div>
240
265
  </div>
241
266
  </div>
242
- </div>
243
- </Layout.Responsive>
267
+ </Layout.Responsive>
268
+ )}
244
269
  </>
245
270
  )
246
271
  }
@@ -14,7 +14,15 @@ type CondtionsProps = {
14
14
  updateConditionsList: Function
15
15
  }
16
16
 
17
- const Conditions: React.FC<CondtionsProps> = ({ conditionControls, conditionLookup, conditionSettings, conditionIndex, removeCondition, selectedColumn, updateConditionsList }) => {
17
+ const Conditions: React.FC<CondtionsProps> = ({
18
+ conditionControls,
19
+ conditionLookup,
20
+ conditionSettings,
21
+ conditionIndex,
22
+ removeCondition,
23
+ selectedColumn,
24
+ updateConditionsList
25
+ }) => {
18
26
  const [openConditionControls, setOpenConditionControls] = conditionControls
19
27
  const showCondition = openConditionControls[conditionIndex]
20
28
  const setShowCondition = (index, value) => {
@@ -43,7 +51,10 @@ const Conditions: React.FC<CondtionsProps> = ({ conditionControls, conditionLook
43
51
  <button onClick={() => setShowCondition(conditionIndex, true)}>
44
52
  <Icon display='caretDown' />
45
53
  </button>
46
- <span> {value ? `${columnName} ${isOrIsNotEqualTo === 'is' ? 'is' : 'is not'} ${value}` : 'New Condition'}</span>
54
+ <span>
55
+ {' '}
56
+ {value ? `${columnName} ${isOrIsNotEqualTo === 'is' ? 'is' : 'is not'} ${value}` : 'New Condition'}
57
+ </span>
47
58
  </div>
48
59
  </>
49
60
  ) : (
@@ -58,7 +69,7 @@ const Conditions: React.FC<CondtionsProps> = ({ conditionControls, conditionLook
58
69
  >
59
70
  <Icon display='caretDown' />
60
71
  </button>
61
- <button className='btn btn-danger btn-sm mt-0 ml-2' onClick={() => removeCondition(conditionIndex)}>
72
+ <button className='btn btn-warn btn-sm mt-0 ml-2' onClick={() => removeCondition(conditionIndex)}>
62
73
  Remove
63
74
  </button>
64
75
  </div>
@@ -66,7 +77,11 @@ const Conditions: React.FC<CondtionsProps> = ({ conditionControls, conditionLook
66
77
  <label className='d-block'>
67
78
  <span>Condition : </span>
68
79
  <div className='pt-1'>
69
- <select className='ml-1' value={columnName} onChange={e => handleConditionChange(e.target.value, 'columnName')}>
80
+ <select
81
+ className='ml-1'
82
+ value={columnName}
83
+ onChange={e => handleConditionChange(e.target.value, 'columnName')}
84
+ >
70
85
  <option value=''>Select</option>
71
86
  {columnNameConditionOptions?.map(columnName => (
72
87
  <option key={columnName} value={columnName}>
@@ -74,7 +89,11 @@ const Conditions: React.FC<CondtionsProps> = ({ conditionControls, conditionLook
74
89
  </option>
75
90
  ))}
76
91
  </select>
77
- <select className='ml-1' value={isOrIsNotEqualTo} onChange={e => handleConditionChange(e.target.value, 'isOrIsNotEqualTo')}>
92
+ <select
93
+ className='ml-1'
94
+ value={isOrIsNotEqualTo}
95
+ onChange={e => handleConditionChange(e.target.value, 'isOrIsNotEqualTo')}
96
+ >
78
97
  <option value='is'>is</option>
79
98
  <option value='isNot'>is not</option>
80
99
  </select>
@@ -23,13 +23,26 @@ import Accordion from '@cdc/core/components/ui/Accordion'
23
23
  import '@cdc/core/styles/v2/components/editor.scss'
24
24
  import './editorPanel.style.css'
25
25
  import VariableSection from './Variables'
26
+ import { CheckBox } from '@cdc/core/components/EditorPanel/Inputs'
26
27
 
27
- const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
28
+ const headerColors = [
29
+ 'theme-blue',
30
+ 'theme-purple',
31
+ 'theme-brown',
32
+ 'theme-teal',
33
+ 'theme-pink',
34
+ 'theme-orange',
35
+ 'theme-slate',
36
+ 'theme-indigo',
37
+ 'theme-cyan',
38
+ 'theme-green',
39
+ 'theme-amber'
40
+ ]
28
41
 
29
42
  const EditorPanel: React.FC = () => {
30
43
  const { config, data, isDashboard, loading, setParentConfig, updateConfig } = useContext(ConfigContext)
31
44
  const { contentEditor, theme, visual } = config
32
- const { inlineHTML, markupVariables, srcUrl, title, useInlineHTML } = contentEditor
45
+ const { inlineHTML, markupVariables, srcUrl, title, useInlineHTML, allowHideSection } = contentEditor
33
46
  const [displayPanel, setDisplayPanel] = useState(true)
34
47
  const updateField = updateFieldFactory(config, updateConfig, true)
35
48
  const hasData = data?.[0] !== undefined ?? false
@@ -111,17 +124,40 @@ const EditorPanel: React.FC = () => {
111
124
  const editorContent = (
112
125
  <Accordion>
113
126
  <Accordion.Section title='General'>
114
- <InputText value={title || ''} section='contentEditor' fieldName='title' label='Title' placeholder='Markup Include Title' updateField={updateField} />
127
+ <InputText
128
+ value={title || ''}
129
+ section='contentEditor'
130
+ fieldName='title'
131
+ label='Title'
132
+ placeholder='Markup Include Title'
133
+ updateField={updateField}
134
+ />
115
135
  </Accordion.Section>
116
136
  <Accordion.Section title='Content Editor'>
117
137
  <span className='divider-heading'>Enter Markup</span>
118
- <InputCheckbox inline value={useInlineHTML} section='contentEditor' fieldName='useInlineHTML' label='Use Inline HTML&nbsp;' updateField={updateField} />
138
+ <InputCheckbox
139
+ inline
140
+ value={useInlineHTML}
141
+ section='contentEditor'
142
+ fieldName='useInlineHTML'
143
+ label='Use Inline HTML&nbsp;'
144
+ updateField={updateField}
145
+ />
119
146
  <div className='column-edit'>
120
147
  {useInlineHTML ? (
121
148
  <>
122
149
  {/* HTML Textbox */}
123
150
  <div ref={textAreaInEditorContainer}>
124
- <InputText value={inlineHTML} section='contentEditor' fieldName='inlineHTML' label='HTML' placeholder='Add HTML here' type='textarea' rows={10} updateField={updateField} />
151
+ <InputText
152
+ value={inlineHTML}
153
+ section='contentEditor'
154
+ fieldName='inlineHTML'
155
+ label='HTML'
156
+ placeholder='Add HTML here'
157
+ type='textarea'
158
+ rows={10}
159
+ updateField={updateField}
160
+ />
125
161
 
126
162
  <hr className='accordion__divider' />
127
163
  </div>
@@ -140,23 +176,69 @@ const EditorPanel: React.FC = () => {
140
176
  </Tooltip>
141
177
  </span>
142
178
  </label>
143
- {hasData === false && <span className='need-data-source-prompt'>To use variables, add data source.</span>}
179
+ {hasData === false && (
180
+ <span className='need-data-source-prompt'>To use variables, add data source.</span>
181
+ )}
144
182
  {variableArray && variableArray.length > 0 && (
145
183
  <div className='section-border'>
146
184
  {variableArray?.map((variableObject, index) => {
147
- return <VariableSection key={`${variableObject.name}-${index}`} controls={openVariableControls} data={data} deleteVariable={deleteVariable} updateVariableArray={updateVariableArray} variableConfig={variableObject} variableIndex={index} />
185
+ return (
186
+ <VariableSection
187
+ key={`${variableObject.name}-${index}`}
188
+ controls={openVariableControls}
189
+ data={data}
190
+ deleteVariable={deleteVariable}
191
+ updateVariableArray={updateVariableArray}
192
+ variableConfig={variableObject}
193
+ variableIndex={index}
194
+ />
195
+ )
148
196
  })}
149
197
  </div>
150
198
  )}
199
+ <div className='pt-2'>
200
+ <CheckBox
201
+ value={allowHideSection}
202
+ section='contentEditor'
203
+ fieldName='allowHideSection'
204
+ label='Hide Section on Null'
205
+ updateField={updateField}
206
+ tooltip={
207
+ <Tooltip style={{ textTransform: 'none' }}>
208
+ <Tooltip.Target>
209
+ <Icon
210
+ display='question'
211
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
212
+ />
213
+ </Tooltip.Target>
214
+ <Tooltip.Content>
215
+ <p>{`Hide this entire Markup Include section if any variable is null or blank.`}</p>
216
+ </Tooltip.Content>
217
+ </Tooltip>
218
+ }
219
+ />
220
+ </div>
221
+
151
222
  <div className='mb-1 d-flex'>
152
- <button className={'btn btn-primary'} onClick={handleCreateNewVariableButtonClick} disabled={!hasData}>
223
+ <button
224
+ className={'btn btn-primary'}
225
+ onClick={handleCreateNewVariableButtonClick}
226
+ disabled={!hasData}
227
+ >
153
228
  Create New Variable
154
229
  </button>
155
230
  </div>
156
231
  </fieldset>
157
232
  </>
158
233
  ) : (
159
- <InputText value={srcUrl || ''} section='contentEditor' fieldName='srcUrl' label='Source URL;' placeholder='https://www.example.com/file.html' updateField={updateField} />
234
+ <InputText
235
+ value={srcUrl || ''}
236
+ section='contentEditor'
237
+ fieldName='srcUrl'
238
+ label='Source URL;'
239
+ placeholder='https://www.example.com/file.html'
240
+ updateField={updateField}
241
+ />
160
242
  )}
161
243
  </div>
162
244
  </Accordion.Section>
@@ -177,11 +259,41 @@ const EditorPanel: React.FC = () => {
177
259
  </ul>
178
260
  </div>
179
261
  <div className='cove-accordion__panel-section checkbox-group'>
180
- <InputCheckbox value={visual.border} section='visual' fieldName='border' label='Display Border&nbsp;' updateField={updateField} />
181
- <InputCheckbox value={visual.borderColorTheme} section='visual' fieldName='borderColorTheme' label='Use Border Color Theme&nbsp;' updateField={updateField} />
182
- <InputCheckbox value={visual.accent} section='visual' fieldName='accent' label='Use Accent Style&nbsp;' updateField={updateField} />
183
- <InputCheckbox value={visual.background} section='visual' fieldName='background' label='Use Theme Background Color&nbsp;' updateField={updateField} />
184
- <InputCheckbox value={visual.hideBackgroundColor} section='visual' fieldName='hideBackgroundColor' label='Hide Background Color&nbsp;' updateField={updateField} />
262
+ <InputCheckbox
263
+ value={visual.border}
264
+ section='visual'
265
+ fieldName='border'
266
+ label='Display Border&nbsp;'
267
+ updateField={updateField}
268
+ />
269
+ <InputCheckbox
270
+ value={visual.borderColorTheme}
271
+ section='visual'
272
+ fieldName='borderColorTheme'
273
+ label='Use Border Color Theme&nbsp;'
274
+ updateField={updateField}
275
+ />
276
+ <InputCheckbox
277
+ value={visual.accent}
278
+ section='visual'
279
+ fieldName='accent'
280
+ label='Use Accent Style&nbsp;'
281
+ updateField={updateField}
282
+ />
283
+ <InputCheckbox
284
+ value={visual.background}
285
+ section='visual'
286
+ fieldName='background'
287
+ label='Use Theme Background Color&nbsp;'
288
+ updateField={updateField}
289
+ />
290
+ <InputCheckbox
291
+ value={visual.hideBackgroundColor}
292
+ section='visual'
293
+ fieldName='hideBackgroundColor'
294
+ label='Hide Background Color&nbsp;'
295
+ updateField={updateField}
296
+ />
185
297
  </div>
186
298
  </Accordion.Section>
187
299
  </Accordion>
@@ -191,7 +303,12 @@ const EditorPanel: React.FC = () => {
191
303
 
192
304
  return (
193
305
  <ErrorBoundary component='EditorPanel'>
194
- <Layout.Sidebar displayPanel={displayPanel} isDashboard={isDashboard} title={'Configure Markup Include'} onBackClick={onBackClick}>
306
+ <Layout.Sidebar
307
+ displayPanel={displayPanel}
308
+ isDashboard={isDashboard}
309
+ title={'Configure Markup Include'}
310
+ onBackClick={onBackClick}
311
+ >
195
312
  {editorContent}
196
313
  </Layout.Sidebar>
197
314
  </ErrorBoundary>
@@ -0,0 +1 @@
1
+ @import '@cdc/core/styles/base';
package/src/index.jsx CHANGED
@@ -5,6 +5,8 @@ import { GlobalContextProvider } from '@cdc/core/components/GlobalContext'
5
5
 
6
6
  import CdcMarkupInclude from './CdcMarkupInclude'
7
7
 
8
+ import './coreStyles_markupinclude.scss'
9
+
8
10
  let isEditor = window.location.href.includes('editor=true')
9
11
 
10
12
  let domContainer = document.getElementsByClassName('react-container')[0]
@@ -14,5 +16,5 @@ ReactDOM.createRoot(domContainer).render(
14
16
  <GlobalContextProvider>
15
17
  <CdcMarkupInclude configUrl={domContainer.attributes['data-config'].value} isEditor={isEditor} />
16
18
  </GlobalContextProvider>
17
- </React.StrictMode>,
19
+ </React.StrictMode>
18
20
  )
@@ -1,5 +1,3 @@
1
- @import '@cdc/core/styles/base';
2
-
3
1
  .markup-include {
4
2
  .checkbox-group {
5
3
  padding: 16px;