@cdc/data-bite 1.1.2 → 1.1.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/dist/cdcdatabite.js +8 -2
- package/examples/example-config.json +6 -2
- package/examples/private/WCMSRD-12345.json +1027 -0
- package/package.json +11 -10
- package/src/CdcDataBite.tsx +323 -76
- package/src/components/CircleCallout.js +3 -3
- package/src/components/EditorPanel.js +265 -42
- package/src/data/initial-state.js +17 -4
- package/src/scss/bite.scss +27 -2
- package/src/scss/editor-panel.scss +50 -0
- package/src/scss/main.scss +6 -2
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { memo, useContext, useEffect, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
Accordion,
|
|
5
5
|
AccordionItem,
|
|
6
|
+
AccordionItemButton,
|
|
6
7
|
AccordionItemHeading,
|
|
7
8
|
AccordionItemPanel,
|
|
8
|
-
|
|
9
|
-
} from 'react-accessible-accordion';
|
|
9
|
+
} from 'react-accessible-accordion'
|
|
10
10
|
|
|
11
|
-
import { useDebounce } from 'use-debounce'
|
|
12
|
-
import Context from '../context'
|
|
13
|
-
import WarningImage from '../images/warning.svg'
|
|
14
|
-
import
|
|
15
|
-
import
|
|
11
|
+
import { useDebounce } from 'use-debounce'
|
|
12
|
+
import Context from '../context'
|
|
13
|
+
import WarningImage from '../images/warning.svg'
|
|
14
|
+
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
15
|
+
import Icon from '@cdc/core/components/ui/Icon'
|
|
16
|
+
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
17
|
+
import { BITE_LOCATIONS, DATA_FUNCTIONS, IMAGE_POSITIONS, DATA_OPERATORS } from '../CdcDataBite'
|
|
16
18
|
|
|
17
|
-
const TextField = memo(({label, section = null, subsection = null, fieldName, updateField, value: stateValue, type = "input", i = null, min = null, max = null, ...attributes}) => {
|
|
19
|
+
const TextField = memo(({label, section = null, subsection = null, fieldName, updateField, value: stateValue, tooltip, type = "input", i = null, min = null, max = null, ...attributes}) => {
|
|
18
20
|
const [ value, setValue ] = useState(stateValue);
|
|
19
21
|
|
|
20
22
|
const [ debouncedValue ] = useDebounce(value, 500);
|
|
@@ -53,17 +55,22 @@ const TextField = memo(({label, section = null, subsection = null, fieldName, up
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
return (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
<>
|
|
59
|
+
{label && label.length > 0 &&
|
|
60
|
+
<label>
|
|
61
|
+
<span className="edit-label column-heading">{label}{tooltip}</span>
|
|
62
|
+
{formElement}
|
|
63
|
+
</label>
|
|
64
|
+
}
|
|
65
|
+
{(!label || label.length === 0) && formElement}
|
|
66
|
+
</>
|
|
60
67
|
)
|
|
61
68
|
})
|
|
62
69
|
|
|
63
|
-
const CheckBox = memo(({label, value, fieldName, section = null, subsection = null, updateField, ...attributes}) => (
|
|
70
|
+
const CheckBox = memo(({label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes}) => (
|
|
64
71
|
<label className="checkbox">
|
|
65
72
|
<input type="checkbox" name={fieldName} checked={ value } onChange={() => { updateField(section, subsection, fieldName, !value) }} {...attributes}/>
|
|
66
|
-
<span className="edit-label">{label}</span>
|
|
73
|
+
<span className="edit-label column-heading">{label}</span><span className="cove-icon">{tooltip}</span>
|
|
67
74
|
</label>
|
|
68
75
|
))
|
|
69
76
|
|
|
@@ -190,14 +197,15 @@ const EditorPanel = memo(() => {
|
|
|
190
197
|
|
|
191
198
|
const convertStateToConfig = () => {
|
|
192
199
|
let strippedState = JSON.parse(JSON.stringify(config))
|
|
193
|
-
if(false === missingRequiredSections()) {
|
|
194
|
-
|
|
195
|
-
}
|
|
200
|
+
//if(false === missingRequiredSections()) {
|
|
201
|
+
//strippedState.newViz
|
|
202
|
+
//}
|
|
196
203
|
delete strippedState.runtime
|
|
197
204
|
|
|
198
205
|
return strippedState
|
|
199
206
|
}
|
|
200
207
|
|
|
208
|
+
// Filters -----------------------------------------------
|
|
201
209
|
const removeFilter = (index) => {
|
|
202
210
|
let filters = [...config.filters];
|
|
203
211
|
|
|
@@ -224,10 +232,12 @@ const EditorPanel = memo(() => {
|
|
|
224
232
|
|
|
225
233
|
const getColumns = (filter = true) => {
|
|
226
234
|
let columns = {}
|
|
235
|
+
if(data.length){
|
|
236
|
+
data.map(row => {
|
|
237
|
+
return Object.keys(row).forEach(columnName => columns[columnName] = true)
|
|
238
|
+
})
|
|
239
|
+
}
|
|
227
240
|
|
|
228
|
-
data.map(row => {
|
|
229
|
-
Object.keys(row).forEach(columnName => columns[columnName] = true)
|
|
230
|
-
})
|
|
231
241
|
|
|
232
242
|
return Object.keys(columns)
|
|
233
243
|
}
|
|
@@ -246,6 +256,54 @@ const EditorPanel = memo(() => {
|
|
|
246
256
|
return filterDataOptions;
|
|
247
257
|
}
|
|
248
258
|
|
|
259
|
+
// Dynamic Images ----------------------------------------
|
|
260
|
+
const updateDynamicImage = (name, index, subindex = null, value) => {
|
|
261
|
+
let imageOptions = [...config.imageData.options];
|
|
262
|
+
null === subindex ? imageOptions[index][name] = value : imageOptions[index].arguments[subindex][name] = value
|
|
263
|
+
|
|
264
|
+
let payload = {...config.imageData, options: imageOptions}
|
|
265
|
+
updateConfig({...config, imageData: payload});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const setDynamicArgument = (optionIndex, name, value) => {
|
|
269
|
+
let imageArguments = [...config.imageData.options[optionIndex].arguments]
|
|
270
|
+
imageArguments[1] = {...imageArguments[1], [name]: value }
|
|
271
|
+
let argumentsPayload = {...config.imageData.options[optionIndex], arguments: imageArguments}
|
|
272
|
+
let optionsPayload = [...config.imageData.options]
|
|
273
|
+
optionsPayload[optionIndex] = argumentsPayload
|
|
274
|
+
let payload = {...config.imageData, options: optionsPayload}
|
|
275
|
+
updateConfig({...config, imageData: payload})
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const removeDynamicArgument = (optionIndex) => {
|
|
279
|
+
if (config.imageData.options[optionIndex].arguments.length > 1) {
|
|
280
|
+
let imageArguments = [...config.imageData.options[optionIndex].arguments]
|
|
281
|
+
imageArguments.pop()
|
|
282
|
+
let argumentsPayload = {...config.imageData.options[optionIndex], arguments: imageArguments}
|
|
283
|
+
let optionsPayload = [...config.imageData.options]
|
|
284
|
+
optionsPayload[optionIndex] = argumentsPayload
|
|
285
|
+
let payload = {...config.imageData, options: optionsPayload}
|
|
286
|
+
updateConfig({...config, imageData: payload})
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const addDynamicImage = () => {
|
|
291
|
+
let imageOptions = config.imageData.options ? [ ...config.imageData.options ] : []
|
|
292
|
+
imageOptions.push({ source: '', arguments: [{ operator: '', threshold: ''}], alt: '', secondArgument: false })
|
|
293
|
+
|
|
294
|
+
let payload = {...config.imageData, options: imageOptions}
|
|
295
|
+
updateConfig({...config, imageData: payload})
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const removeDynamicImage = (index) => {
|
|
299
|
+
let imageOptions = [...config.imageData.options];
|
|
300
|
+
imageOptions.splice(index, 1);
|
|
301
|
+
|
|
302
|
+
let payload = {...config.imageData, options: imageOptions}
|
|
303
|
+
updateConfig({...config, imageData: payload});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// General -----------------------------------------------
|
|
249
307
|
if(loading) {
|
|
250
308
|
return null
|
|
251
309
|
}
|
|
@@ -254,8 +312,8 @@ const EditorPanel = memo(() => {
|
|
|
254
312
|
<ErrorBoundary component="EditorPanel">
|
|
255
313
|
{!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error /> }
|
|
256
314
|
{(!config.dataColumn || !config.dataFunction) && <Confirm />}
|
|
257
|
-
<button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick}
|
|
258
|
-
<section className={displayPanel ? 'editor-panel' : 'hidden editor-panel'}>
|
|
315
|
+
<button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick} />
|
|
316
|
+
<section className={displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'}>
|
|
259
317
|
<div className="heading-2">Configure Data Bite</div>
|
|
260
318
|
<section className="form-container">
|
|
261
319
|
<form>
|
|
@@ -269,12 +327,35 @@ const EditorPanel = memo(() => {
|
|
|
269
327
|
<AccordionItemPanel>
|
|
270
328
|
<Select value={config.biteStyle} fieldName="biteStyle" label="Data Bite Style" updateField={updateField} options={BITE_LOCATIONS} initial="Select" />
|
|
271
329
|
<TextField value={config.title} fieldName="title" label="Title" placeholder="Data Bite Title" updateField={updateField} />
|
|
272
|
-
<TextField type="textarea" value={config.biteBody} fieldName="biteBody" label="Message" updateField={updateField}
|
|
273
|
-
|
|
330
|
+
<TextField type="textarea" value={config.biteBody} fieldName="biteBody" label="Message" updateField={updateField} tooltip={
|
|
331
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
332
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
333
|
+
<Tooltip.Content>
|
|
334
|
+
<p>Enter the message text for the visualization. The following HTML tags are supported: strong, em, sup, and sub.</p>
|
|
335
|
+
</Tooltip.Content>
|
|
336
|
+
</Tooltip>
|
|
337
|
+
}/>
|
|
338
|
+
<TextField value={config.subtext} fieldName="subtext" label="Subtext/Citation" placeholder="Data Bite Subtext or Citation" updateField={updateField} tooltip={
|
|
339
|
+
<Tooltip style={{textTransform: 'none'}}>
|
|
340
|
+
<Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
|
|
341
|
+
<Tooltip.Content>
|
|
342
|
+
<p>
|
|
343
|
+
Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
|
|
344
|
+
</Tooltip.Content>
|
|
345
|
+
</Tooltip>
|
|
346
|
+
}/>
|
|
347
|
+
<CheckBox value={config.general.isCompactStyle} section="general" fieldName="isCompactStyle" label="Compact Style" updateField={updateField} tooltip={
|
|
348
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
349
|
+
<Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }} /></Tooltip.Target>
|
|
350
|
+
<Tooltip.Content>
|
|
351
|
+
<p>Simple data bite style that formats certain elements for a more compact view.</p>
|
|
352
|
+
</Tooltip.Content>
|
|
353
|
+
</Tooltip>
|
|
354
|
+
} />
|
|
274
355
|
</AccordionItemPanel>
|
|
275
356
|
</AccordionItem>
|
|
276
357
|
|
|
277
|
-
<AccordionItem>
|
|
358
|
+
<AccordionItem> {/*Data*/}
|
|
278
359
|
<AccordionItemHeading>
|
|
279
360
|
<AccordionItemButton>
|
|
280
361
|
Data {(!config.dataColumn || !config.dataFunction) && <WarningImage width="25" className="warning-icon" />}
|
|
@@ -292,23 +373,37 @@ const EditorPanel = memo(() => {
|
|
|
292
373
|
<li className="three-col">
|
|
293
374
|
<TextField value={config.dataFormat.prefix} section="dataFormat" fieldName="prefix" label="Prefix" updateField={updateField} />
|
|
294
375
|
<TextField value={config.dataFormat.suffix} section="dataFormat" fieldName="suffix" label="Suffix" updateField={updateField} />
|
|
295
|
-
<TextField
|
|
376
|
+
<TextField type="number" value={config.dataFormat.roundToPlace} section="dataFormat" fieldName="roundToPlace" label="Round" updateField={updateField} min='0' max='99' />
|
|
296
377
|
</li>
|
|
297
378
|
</ul>
|
|
298
379
|
<CheckBox value={config.dataFormat.commas} section="dataFormat" fieldName="commas" label="Add commas" updateField={updateField} />
|
|
380
|
+
<CheckBox value={config.dataFormat.ignoreZeros} section="dataFormat" fieldName="ignoreZeros" label="Ignore Zeros" updateField={updateField} />
|
|
299
381
|
<hr className="accordion__divider" />
|
|
382
|
+
|
|
383
|
+
<label style={{marginBottom: '1rem'}}>
|
|
384
|
+
<span className="edit-label">
|
|
385
|
+
Data Point Filters
|
|
386
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
387
|
+
<Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
|
|
388
|
+
<Tooltip.Content>
|
|
389
|
+
<p>To refine the highlighted data point, specify one or more filters (e.g., "Male" and
|
|
390
|
+
"Female" for a column called "Sex").</p>
|
|
391
|
+
</Tooltip.Content>
|
|
392
|
+
</Tooltip>
|
|
393
|
+
</span>
|
|
394
|
+
</label>
|
|
300
395
|
{
|
|
301
396
|
config.filters &&
|
|
302
397
|
<ul className="filters-list">
|
|
303
398
|
{config.filters.map((filter, index) => (
|
|
304
|
-
<fieldset className="edit-block">
|
|
399
|
+
<fieldset className="edit-block" key={index}>
|
|
305
400
|
<button type="button" className="remove-column" onClick={() => {removeFilter(index)}}>Remove</button>
|
|
306
401
|
<label>
|
|
307
402
|
<span className="edit-label column-heading">Column</span>
|
|
308
|
-
<select value={filter.columnName} onChange={(e) => {updateFilterProp('columnName', index, e.target.value)}}>
|
|
403
|
+
<select value={filter.columnName ? filter.columnName : ''} onChange={(e) => {updateFilterProp('columnName', index, e.target.value)}}>
|
|
309
404
|
<option value="">- Select Option -</option>
|
|
310
|
-
{getColumns().map((dataKey) => (
|
|
311
|
-
<option value={dataKey}>{dataKey}</option>
|
|
405
|
+
{getColumns().map((dataKey, index) => (
|
|
406
|
+
<option value={dataKey} key={index}>{dataKey}</option>
|
|
312
407
|
))}
|
|
313
408
|
</select>
|
|
314
409
|
</label>
|
|
@@ -316,8 +411,8 @@ const EditorPanel = memo(() => {
|
|
|
316
411
|
<span className="edit-label column-heading">Column Value</span>
|
|
317
412
|
<select value={filter.columnValue} onChange={(e) => {updateFilterProp('columnValue', index, e.target.value)}}>
|
|
318
413
|
<option value="">- Select Option -</option>
|
|
319
|
-
{getFilterColumnValues(index).map((dataKey) => (
|
|
320
|
-
<option value={dataKey}>{dataKey}</option>
|
|
414
|
+
{getFilterColumnValues(index).map((dataKey, index) => (
|
|
415
|
+
<option value={dataKey} key={index}>{dataKey}</option>
|
|
321
416
|
))}
|
|
322
417
|
</select>
|
|
323
418
|
</label>
|
|
@@ -325,23 +420,24 @@ const EditorPanel = memo(() => {
|
|
|
325
420
|
))}
|
|
326
421
|
</ul>
|
|
327
422
|
}
|
|
328
|
-
{(!config.filters || config.filters.length === 0) &&
|
|
423
|
+
{(!config.filters || config.filters.length === 0) &&
|
|
424
|
+
<div>
|
|
425
|
+
<fieldset className="edit-block">
|
|
426
|
+
<p style={{textAlign: "center"}}>There are currently no filters.</p>
|
|
427
|
+
</fieldset>
|
|
428
|
+
</div>
|
|
429
|
+
}
|
|
329
430
|
<button type="button" onClick={addNewFilter} className="btn full-width">Add Filter</button>
|
|
330
431
|
</AccordionItemPanel>
|
|
331
432
|
</AccordionItem>
|
|
332
433
|
|
|
333
|
-
<AccordionItem>
|
|
434
|
+
<AccordionItem> {/*Visual*/}
|
|
334
435
|
<AccordionItemHeading>
|
|
335
436
|
<AccordionItemButton>
|
|
336
437
|
Visual
|
|
337
438
|
</AccordionItemButton>
|
|
338
439
|
</AccordionItemHeading>
|
|
339
440
|
<AccordionItemPanel>
|
|
340
|
-
|
|
341
|
-
{['title', 'body'].includes(config.biteStyle) &&
|
|
342
|
-
<TextField value={config.imageUrl} fieldName="imageUrl" label="Image URL" updateField={updateField} />
|
|
343
|
-
}
|
|
344
|
-
<Select value={config.bitePosition || ""} fieldName="bitePosition" label="Image/Graphic Position" updateField={updateField} initial="Select" options={IMAGE_POSITIONS} />
|
|
345
441
|
<TextField type="number" value={config.biteFontSize} fieldName="biteFontSize" label="Bite Font Size" updateField={updateField} min="16" max="65" />
|
|
346
442
|
<Select value={config.fontSize} fieldName="fontSize" label="Overall Font Size" updateField={updateField} options={['small', 'medium', 'large']} />
|
|
347
443
|
<CheckBox value={config.shadow} fieldName="shadow" label="Display Shadow" updateField={updateField} />
|
|
@@ -349,13 +445,140 @@ const EditorPanel = memo(() => {
|
|
|
349
445
|
<span className="edit-label">Theme</span>
|
|
350
446
|
<ul className="color-palette">
|
|
351
447
|
{headerColors.map( (palette) => (
|
|
352
|
-
<li title={ palette } key={ palette } onClick={ () => { updateConfig({...config, theme: palette})}} className={ config.theme === palette ? "selected " + palette : palette}
|
|
353
|
-
</li>
|
|
448
|
+
<li title={ palette } key={ palette } onClick={ () => { updateConfig({...config, theme: palette})}} className={ config.theme === palette ? "selected " + palette : palette} />
|
|
354
449
|
))}
|
|
355
450
|
</ul>
|
|
356
451
|
</label>
|
|
452
|
+
{/* <div className="cove-accordion__panel-section">
|
|
453
|
+
<CheckBox value={config.visual.border} section="visual" fieldName="border" label="Display Border" updateField={updateField} />
|
|
454
|
+
<CheckBox value={config.visual.borderColorTheme} section="visual" fieldName="borderColorTheme" label="Use Border Color Theme" updateField={updateField} />
|
|
455
|
+
<CheckBox value={config.visual.accent} section="visual" fieldName="accent" label="Use Accent Style" updateField={updateField} />
|
|
456
|
+
<CheckBox value={config.visual.background} section="visual" fieldName="background" label="Use Theme Background Color" updateField={updateField} />
|
|
457
|
+
<CheckBox value={config.visual.hideBackgroundColor} section="visual" fieldName="hideBackgroundColor" label="Hide Background Color" updateField={updateField} />
|
|
458
|
+
</div> */}
|
|
357
459
|
</AccordionItemPanel>
|
|
358
460
|
</AccordionItem>
|
|
461
|
+
|
|
462
|
+
{['title', 'body', 'graphic'].includes(config.biteStyle) &&
|
|
463
|
+
<AccordionItem> {/*Image & Dynamic Images*/}
|
|
464
|
+
<AccordionItemHeading>
|
|
465
|
+
<AccordionItemButton>
|
|
466
|
+
Image{[ 'dynamic' ].includes(config.imageData.display) && 's'}
|
|
467
|
+
</AccordionItemButton>
|
|
468
|
+
</AccordionItemHeading>
|
|
469
|
+
|
|
470
|
+
<AccordionItemPanel>
|
|
471
|
+
<Select value={config.imageData.display || ""} section="imageData" fieldName="display" label="Image Display Type" updateField={updateField} options={['none', 'static', 'dynamic']} />
|
|
472
|
+
<Select value={config.bitePosition || ""} fieldName="bitePosition" label="Image/Graphic Position" updateField={updateField} initial="Select" options={IMAGE_POSITIONS} />
|
|
473
|
+
{['static'].includes(config.imageData.display) &&
|
|
474
|
+
<>
|
|
475
|
+
<TextField value={config.imageData.url} section="imageData" fieldName="url" label="Image URL" updateField={updateField} />
|
|
476
|
+
<TextField value={config.imageData.alt} section="imageData" fieldName="alt" label="Alt Text" updateField={updateField} />
|
|
477
|
+
</>
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
{[ 'dynamic' ].includes(config.imageData.display) &&
|
|
481
|
+
<>
|
|
482
|
+
<TextField value={config.imageData.url || ""} section="imageData" fieldName="url" label="Image URL (default)" updateField={updateField} />
|
|
483
|
+
<TextField value={config.imageData.alt} section="imageData" fieldName="alt" label="Alt Text (default)" updateField={updateField} />
|
|
484
|
+
|
|
485
|
+
<hr className="accordion__divider" />
|
|
486
|
+
|
|
487
|
+
{(!config.imageData.options || config.imageData.options.length === 0) && <p style={{textAlign: "center"}}>There are currently no dynamic images.</p>}
|
|
488
|
+
{config.imageData.options && config.imageData.options.length > 0 &&
|
|
489
|
+
<>
|
|
490
|
+
<ul>
|
|
491
|
+
{config.imageData.options.map((option, index) => (
|
|
492
|
+
<fieldset className="edit-block" key={index}>
|
|
493
|
+
<button type="button" className="remove-column" onClick={() => {removeDynamicImage(index)}}>Remove</button>
|
|
494
|
+
<label>
|
|
495
|
+
<span className="edit-label column-heading"><strong>{'Image #' + (index + 1)}</strong></span>
|
|
496
|
+
|
|
497
|
+
<div className="accordion__panel-row align-center">
|
|
498
|
+
<div className="accordion__panel-col flex-auto">
|
|
499
|
+
If Value
|
|
500
|
+
</div>
|
|
501
|
+
<div className="accordion__panel-col flex-auto">
|
|
502
|
+
<select value={option.arguments[0]?.operator || ""} onChange={(e) => {updateDynamicImage('operator', index, 0, e.target.value)}}>
|
|
503
|
+
<option value="" disabled/>
|
|
504
|
+
{DATA_OPERATORS.map((operator, index) => (
|
|
505
|
+
<option value={operator} key={index}>{operator}</option>
|
|
506
|
+
))}
|
|
507
|
+
</select>
|
|
508
|
+
</div>
|
|
509
|
+
<div className="accordion__panel-col flex-grow flex-shrink">
|
|
510
|
+
<input type="number" value={option.arguments[0]?.threshold || ""} onChange={(e) => {updateDynamicImage('threshold', index, 0, e.target.value)}} />
|
|
511
|
+
</div>
|
|
512
|
+
</div>
|
|
513
|
+
|
|
514
|
+
<div className="accordion__panel-row mb-2 align-center">
|
|
515
|
+
<div className="accordion__panel-col flex-grow">
|
|
516
|
+
<select className='border-dashed text-center' value={option.secondArgument ? 'and' : 'then'} onChange={(e) => {
|
|
517
|
+
if ('then' === e.target.value) {updateDynamicImage('secondArgument', index, null,false); removeDynamicArgument(index)}
|
|
518
|
+
if ('and' === e.target.value) {updateDynamicImage('secondArgument', index, null,true)}
|
|
519
|
+
}}>
|
|
520
|
+
<option value={'then'}>Then</option>
|
|
521
|
+
<option value={'and'}>And</option>
|
|
522
|
+
</select>
|
|
523
|
+
</div>
|
|
524
|
+
</div>
|
|
525
|
+
|
|
526
|
+
{option.secondArgument && true === option.secondArgument &&
|
|
527
|
+
<>
|
|
528
|
+
<div className="accordion__panel-row align-center">
|
|
529
|
+
<div className="accordion__panel-col flex-auto">
|
|
530
|
+
If Value
|
|
531
|
+
</div>
|
|
532
|
+
<div className="accordion__panel-col flex-auto">
|
|
533
|
+
<select value={option.arguments[1]?.operator || ""} onChange={(e) => {setDynamicArgument(index, 'operator', e.target.value)}}>
|
|
534
|
+
<option value="" disabled/>
|
|
535
|
+
{DATA_OPERATORS.map((operator, index) => (
|
|
536
|
+
<option value={operator} key={index}>{operator}</option>
|
|
537
|
+
))}
|
|
538
|
+
</select>
|
|
539
|
+
</div>
|
|
540
|
+
<div className="accordion__panel-col flex-grow flex-shrink">
|
|
541
|
+
<input type="number" value={option.arguments[1]?.threshold || ""} onChange={(e) => {setDynamicArgument(index, 'threshold', e.target.value)}} />
|
|
542
|
+
</div>
|
|
543
|
+
</div>
|
|
544
|
+
<div className="accordion__panel-row mb-2 align-center text-center text-capitalize">
|
|
545
|
+
<div className="accordion__panel-col flex-grow">
|
|
546
|
+
Then
|
|
547
|
+
</div>
|
|
548
|
+
</div>
|
|
549
|
+
</>
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
<div className="accordion__panel-row mb-2 align-center">
|
|
553
|
+
<div className="accordion__panel-col flex-auto">
|
|
554
|
+
Show
|
|
555
|
+
</div>
|
|
556
|
+
<div className="accordion__panel-col flex-grow">
|
|
557
|
+
<input type="text" value={option.source || ""} onChange={(e) => {updateDynamicImage('source', index, null, e.target.value)}} />
|
|
558
|
+
</div>
|
|
559
|
+
</div>
|
|
560
|
+
|
|
561
|
+
<div className="accordion__panel-row mb-2 align-center">
|
|
562
|
+
<div className="accordion__panel-col flex-auto">
|
|
563
|
+
Alt Text
|
|
564
|
+
</div>
|
|
565
|
+
<div className="accordion__panel-col flex-grow">
|
|
566
|
+
<input type="text" value={option.alt || ""} onChange={(e) => {updateDynamicImage('alt', index, null, e.target.value)}} />
|
|
567
|
+
</div>
|
|
568
|
+
</div>
|
|
569
|
+
</label>
|
|
570
|
+
</fieldset>
|
|
571
|
+
))}
|
|
572
|
+
</ul>
|
|
573
|
+
</>
|
|
574
|
+
}
|
|
575
|
+
<button type="button" onClick={addDynamicImage} className="btn full-width">Add Dynamic Image</button>
|
|
576
|
+
</>
|
|
577
|
+
}
|
|
578
|
+
</AccordionItemPanel>
|
|
579
|
+
</AccordionItem>
|
|
580
|
+
}
|
|
581
|
+
|
|
359
582
|
</Accordion>
|
|
360
583
|
</form>
|
|
361
584
|
</section>
|
|
@@ -7,10 +7,13 @@ export default {
|
|
|
7
7
|
bitePosition: "Left",
|
|
8
8
|
biteFontSize: 24,
|
|
9
9
|
fontSize: "medium",
|
|
10
|
-
imageUrl: "",
|
|
11
10
|
biteBody: "",
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
imageData: {
|
|
12
|
+
display: "none",
|
|
13
|
+
url: "",
|
|
14
|
+
alt: "",
|
|
15
|
+
options: []
|
|
16
|
+
},
|
|
14
17
|
dataFormat: {
|
|
15
18
|
roundToPlace: 0,
|
|
16
19
|
commas: true,
|
|
@@ -23,4 +26,14 @@ export default {
|
|
|
23
26
|
title: "",
|
|
24
27
|
theme: "theme-blue",
|
|
25
28
|
shadow: false,
|
|
26
|
-
|
|
29
|
+
visual: {
|
|
30
|
+
border: false,
|
|
31
|
+
accent: false,
|
|
32
|
+
background: false,
|
|
33
|
+
hideBackgroundColor: false,
|
|
34
|
+
borderColorTheme: false
|
|
35
|
+
},
|
|
36
|
+
general: {
|
|
37
|
+
isCompactStyle: false
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/scss/bite.scss
CHANGED
|
@@ -110,8 +110,9 @@
|
|
|
110
110
|
padding: 0 1em;
|
|
111
111
|
left: 0;
|
|
112
112
|
top: 0;
|
|
113
|
-
|
|
113
|
+
padding: 0.6rem 0.8rem;
|
|
114
114
|
color: white;
|
|
115
|
+
font-size:1.1em;
|
|
115
116
|
&:empty {
|
|
116
117
|
min-height: 5px;
|
|
117
118
|
}
|
|
@@ -127,6 +128,17 @@
|
|
|
127
128
|
border-top: none;
|
|
128
129
|
background: $lightestGray;
|
|
129
130
|
border: solid 1px $lightGray;
|
|
131
|
+
border-bottom-left-radius: 3px;
|
|
132
|
+
border-bottom-right-radius: 3px;
|
|
133
|
+
|
|
134
|
+
&-header {
|
|
135
|
+
border-top-left-radius: 3px;
|
|
136
|
+
border-top-right-radius: 3px;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
&.no-borders {
|
|
140
|
+
border: none;
|
|
141
|
+
}
|
|
130
142
|
|
|
131
143
|
&.shadow {
|
|
132
144
|
box-shadow: rgba(0, 0, 0, 0.2) 0 3px 10px;
|
|
@@ -265,7 +277,6 @@
|
|
|
265
277
|
|
|
266
278
|
.bite-text {
|
|
267
279
|
margin-bottom: 15px;
|
|
268
|
-
font-size: 0.9em;
|
|
269
280
|
color: #222;
|
|
270
281
|
flex: 1 0 auto;
|
|
271
282
|
}
|
|
@@ -345,5 +356,19 @@
|
|
|
345
356
|
}
|
|
346
357
|
}
|
|
347
358
|
}
|
|
359
|
+
|
|
360
|
+
// General: Compact View
|
|
361
|
+
&.bite--isCompactStyle .bite .cove-component__content .bite-content {
|
|
362
|
+
align-items: center;
|
|
363
|
+
p.bite-text {
|
|
364
|
+
margin-bottom: 0;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
&.bite--isCompactStyle .bite .cove-component__content {
|
|
369
|
+
align-items: center;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.cove-component__header + .bite { border-top: 0; }
|
|
348
373
|
}
|
|
349
374
|
}
|
|
@@ -7,6 +7,17 @@
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
.editor-panel {
|
|
10
|
+
//TODO: Remove after COVE refactor
|
|
11
|
+
&.cove {
|
|
12
|
+
@import "@cdc/core/styles/v2/layout/tooltip.scss";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.text-center {
|
|
16
|
+
text-align: center;
|
|
17
|
+
}
|
|
18
|
+
.text-capitalize {
|
|
19
|
+
text-transform: capitalize;
|
|
20
|
+
}
|
|
10
21
|
.two-col-inputs {
|
|
11
22
|
display: flex;
|
|
12
23
|
margin-top: 1em;
|
|
@@ -144,6 +155,45 @@
|
|
|
144
155
|
h5 {
|
|
145
156
|
font-size: .8em;
|
|
146
157
|
}
|
|
158
|
+
|
|
159
|
+
.accordion__panel-row {
|
|
160
|
+
display: flex;
|
|
161
|
+
justify-content: flex-start;
|
|
162
|
+
margin-left: -4px;
|
|
163
|
+
margin-right: -4px;
|
|
164
|
+
margin-bottom: 0.75em
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.accordion__panel-col {
|
|
168
|
+
flex: 0 0 0;
|
|
169
|
+
padding-left: 4px;
|
|
170
|
+
padding-right: 4px;
|
|
171
|
+
|
|
172
|
+
select {
|
|
173
|
+
padding: 0.425em 0.5em;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
select.border-dashed {
|
|
177
|
+
border: rgba(0, 0, 0, 0.3) 1px dashed !important;
|
|
178
|
+
border-radius: 0.25rem;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.d-flex {
|
|
183
|
+
display: flex;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.align-center {
|
|
187
|
+
align-items: center;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.justify-end {
|
|
191
|
+
justify-content: flex-end;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.flex-grow { flex-grow: 1; }
|
|
195
|
+
.flex-shrink { flex-shrink: 1; }
|
|
196
|
+
.flex-auto { flex-basis: auto; }
|
|
147
197
|
}
|
|
148
198
|
|
|
149
199
|
.advanced {
|
package/src/scss/main.scss
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
@import '~@cdc/core/styles/base';
|
|
2
2
|
@import "~@cdc/core/styles/heading-colors";
|
|
3
|
+
@import "~@cdc/core/styles/v2/themes/color-definitions";
|
|
3
4
|
@import 'variables';
|
|
4
5
|
|
|
5
6
|
.cdc-open-viz-module.type-data-bite {
|
|
@@ -39,9 +40,12 @@
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
.warning-icon {
|
|
43
|
+
position: relative;
|
|
44
|
+
top: 2px;
|
|
42
45
|
width: 15px;
|
|
43
46
|
height: 15px;
|
|
44
|
-
margin-
|
|
47
|
+
margin-left: 5px;
|
|
48
|
+
|
|
45
49
|
path {
|
|
46
50
|
fill: #d8000c;
|
|
47
51
|
}
|
|
@@ -65,4 +69,4 @@
|
|
|
65
69
|
font-size: 1.1em !important;
|
|
66
70
|
}
|
|
67
71
|
// Medium is just the default
|
|
68
|
-
}
|
|
72
|
+
}
|