@cdc/waffle-chart 1.0.0 → 1.0.2

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,120 +1,31 @@
1
1
  import React, { useState, useEffect, memo, useContext } from 'react'
2
2
 
3
- import {
4
- Accordion,
5
- AccordionItem,
6
- AccordionItemHeading,
7
- AccordionItemPanel,
8
- AccordionItemButton,
9
- } from 'react-accessible-accordion'
10
-
11
- import { useDebounce } from 'use-debounce'
12
- import Context from '../context'
13
3
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
14
- import { DATA_OPERATORS, DATA_FUNCTIONS } from '../CdcWaffleChart'
15
-
16
- const TextField = memo((
17
- {
18
- label,
19
- section = null,
20
- subsection = null,
21
- fieldName,
22
- updateField,
23
- value: stateValue,
24
- type = 'input',
25
- i = null, min = null, max = null,
26
- ...attributes
27
- }
28
- ) => {
29
-
30
- const [ value, setValue ] = useState(stateValue)
31
- const [ debouncedValue ] = useDebounce(value, 500)
32
-
33
- useEffect(() => {
34
- if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
35
- updateField(section, subsection, fieldName, debouncedValue, i)
36
- }
37
- }, [ debouncedValue, section, subsection, fieldName, i, stateValue, updateField ])
38
-
39
- let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
40
-
41
- const onChange = (e) => {
42
- if ('number' !== type || min === null) {
43
- setValue(e.target.value)
44
- } else {
45
- if (!e.target.value || (parseFloat(min) <= parseFloat(e.target.value) & parseFloat(max) >= parseFloat(e.target.value))) {
46
- setValue(e.target.value)
47
- } else {
48
- setValue(min.toString())
49
- }
50
- }
51
- }
52
4
 
53
- let formElement = <input type="text" name={name} onChange={onChange} {...attributes} value={value}/>
5
+ import ConfigContext from '../ConfigContext'
54
6
 
55
- if ('textarea' === type) {
56
- formElement = (
57
- <textarea name={name} onChange={onChange} {...attributes} value={value}/>
58
- )
59
- }
7
+ import Accordion from '@cdc/core/components/ui/Accordion'
8
+ import Button from '@cdc/core/components/elements/Button'
9
+ import Icon from '@cdc/core/components/ui/Icon'
10
+ import Tooltip from '@cdc/core/components/ui/Tooltip'
11
+ import InputText from '@cdc/core/components/inputs/InputText'
12
+ import InputSelect from '@cdc/core/components/inputs/InputSelect'
13
+ import InputCheckbox from '@cdc/core/components/inputs/InputCheckbox'
60
14
 
61
- if ('number' === type) {
62
- formElement = <input type="number" name={name} onChange={onChange} {...attributes} value={value}/>
63
- }
15
+ import '@cdc/core/styles/v2/components/editor.scss'
64
16
 
65
- return (
66
- <label>
67
- {label && <span className="edit-label column-heading">{label}</span>}
68
- {formElement}
69
- </label>
70
- )
71
- })
72
-
73
- const Select = memo((
74
- {
75
- label,
76
- value,
77
- options,
78
- fieldName,
79
- section = null,
80
- subsection = null,
81
- required = false,
82
- updateField,
83
- initial: initialValue,
84
- ...attributes
85
- }
86
- ) => {
87
-
88
- let optionsJsx = ''
89
-
90
- if (Array.isArray(options)) { //Handle basic array
91
- optionsJsx = options.map(optionName => <option value={optionName} key={optionName}>{optionName}</option>)
92
- } else { //Handle object with value/name pairs
93
- optionsJsx = []
94
- for (const [ optionValue, optionName ] of Object.entries(options)) {
95
- optionsJsx.push(<option value={optionValue} key={optionValue}>{optionName}</option>)
96
- }
97
- }
98
-
99
- if (initialValue) {
100
- optionsJsx.unshift(<option value="" key="initial">{initialValue}</option>)
101
- }
102
-
103
- return (
104
- <label>
105
- {label && <span className="edit-label">{label}</span>}
106
- <select className={required && !value ? 'warning' : ''} name={fieldName} value={value} onChange={(event) => {
107
- updateField(section, subsection, fieldName, event.target.value)
108
- }} {...attributes}>
109
- {optionsJsx}
110
- </select>
111
- </label>
112
- )
113
- })
17
+ import { DATA_OPERATORS, DATA_FUNCTIONS } from '../CdcWaffleChart'
114
18
 
115
19
  const headerColors = [ 'theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber' ]
116
20
 
117
- const EditorPanel = memo(() => {
21
+ const CheckBox = memo(({ label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes }) => (
22
+ <label className="checkbox">
23
+ <input type="checkbox" name={fieldName} checked={value} onChange={() => { updateField(section, subsection, fieldName, !value) }} {...attributes} />
24
+ <span className="edit-label column-heading">{label}</span><span className="cove-icon">{tooltip}</span>
25
+ </label>
26
+ ))
27
+
28
+ const EditorPanel = memo((props) => {
118
29
  const {
119
30
  config,
120
31
  updateConfig,
@@ -122,13 +33,10 @@ const EditorPanel = memo(() => {
122
33
  data,
123
34
  setParentConfig,
124
35
  isDashboard
125
- } = useContext(Context)
36
+ } = useContext(ConfigContext)
126
37
 
127
38
  const [ displayPanel, setDisplayPanel ] = useState(true)
128
-
129
- const enforceRestrictions = (updatedConfig) => {
130
- //If there are any dependencies between fields, etc../
131
- }
39
+ const [ showConfigConfirm, setShowConfigConfirm ] = useState(false)
132
40
 
133
41
  const updateField = (section, subsection, fieldName, newValue) => {
134
42
  // Top level
@@ -139,8 +47,6 @@ const EditorPanel = memo(() => {
139
47
  updatedConfig.filterValue = ''
140
48
  }
141
49
 
142
- enforceRestrictions(updatedConfig)
143
-
144
50
  updateConfig(updatedConfig)
145
51
  return
146
52
  }
@@ -159,29 +65,34 @@ const EditorPanel = memo(() => {
159
65
  sectionValue = { ...config[section], [subsection]: { ...config[section][subsection], [fieldName]: newValue } }
160
66
  }
161
67
  }
162
-
163
68
  let updatedConfig = { ...config, [section]: sectionValue }
164
69
 
165
- enforceRestrictions(updatedConfig)
166
-
167
70
  updateConfig(updatedConfig)
168
71
  }
169
72
 
170
- const missingRequiredSections = () => {
171
- //Whether to show error message if something is required to show a data-bite and isn't filled in
172
- return false
173
- }
174
-
175
73
  useEffect(() => {
74
+
75
+ console.log('updating parent')
76
+ console.log(setParentConfig)
176
77
  // Pass up to Editor if needed
177
78
  if (setParentConfig) {
178
79
  const newConfig = convertStateToConfig()
179
80
 
81
+ console.log('newConfig', newConfig)
82
+
180
83
  setParentConfig(newConfig)
181
84
  }
182
85
  // eslint-disable-next-line react-hooks/exhaustive-deps
183
86
  }, [ config ])
184
87
 
88
+ useEffect(()=> {
89
+ if (!showConfigConfirm) {
90
+ let newConfig = { ...config }
91
+ delete newConfig.newViz
92
+ updateConfig(newConfig)
93
+ }
94
+ }, [])
95
+
185
96
  useEffect(() => {
186
97
  //Verify comparate data type
187
98
  let operators = [ '<', '>', '<=', '>=' ]
@@ -199,11 +110,13 @@ const EditorPanel = memo(() => {
199
110
  }, [ config.dataConditionalOperator, config.dataConditionalComparate ])
200
111
 
201
112
  const onBackClick = () => {
202
- if (isDashboard) {
203
- updateConfig({ ...config, editing: false })
204
- } else {
205
- setDisplayPanel(!displayPanel)
206
- }
113
+ setDisplayPanel(!displayPanel)
114
+
115
+ // if (isDashboard) {
116
+ // updateConfig({ ...config, editing: false })
117
+ // } else {
118
+ // setDisplayPanel(!displayPanel)
119
+ // }
207
120
  }
208
121
 
209
122
  const Error = () => {
@@ -218,13 +131,10 @@ const EditorPanel = memo(() => {
218
131
  }
219
132
 
220
133
  const Confirm = () => {
221
-
222
134
  const confirmDone = (e) => {
223
135
  e.preventDefault()
224
-
225
- let newConfig = {...config}
136
+ let newConfig = { ...config }
226
137
  delete newConfig.newViz
227
-
228
138
  updateConfig(newConfig)
229
139
  }
230
140
 
@@ -233,7 +143,7 @@ const EditorPanel = memo(() => {
233
143
  <section className="waiting-container">
234
144
  <h3>Finish Configuring</h3>
235
145
  <p>Set all required options to the left and confirm below to display a preview of the chart.</p>
236
- <button className="btn" style={{ margin: '1em auto' }} disabled={missingRequiredSections()} onClick={confirmDone}>I'm Done</button>
146
+ <button className="btn" style={{ margin: '1em auto' }} onClick={confirmDone}>I'm Done</button>
237
147
  </section>
238
148
  </section>
239
149
  )
@@ -241,35 +151,27 @@ const EditorPanel = memo(() => {
241
151
 
242
152
  const convertStateToConfig = () => {
243
153
  let strippedState = JSON.parse(JSON.stringify(config))
244
- if (false === missingRequiredSections()) {
245
- delete strippedState.newViz
246
- }
154
+ delete strippedState.newViz
247
155
  delete strippedState.runtime
248
156
 
249
157
  return strippedState
250
158
  }
251
159
 
160
+ const addNewFilter = () => {
161
+ let filters = config.filters ? [ ...config.filters ] : []
162
+ filters.push({ values: [] })
163
+ updateConfig({ ...config, filters })
164
+ }
165
+
252
166
  const removeFilter = (index) => {
253
167
  let filters = [ ...config.filters ]
254
-
255
168
  filters.splice(index, 1)
256
-
257
169
  updateConfig({ ...config, filters })
258
170
  }
259
171
 
260
172
  const updateFilterProp = (name, index, value) => {
261
173
  let filters = [ ...config.filters ]
262
-
263
174
  filters[index][name] = value
264
-
265
- updateConfig({ ...config, filters })
266
- }
267
-
268
- const addNewFilter = () => {
269
- let filters = config.filters ? [ ...config.filters ] : []
270
-
271
- filters.push({ values: [] })
272
-
273
175
  updateConfig({ ...config, filters })
274
176
  }
275
177
 
@@ -295,214 +197,243 @@ const EditorPanel = memo(() => {
295
197
  return filterDataOptions
296
198
  }
297
199
 
298
- const toggleCustomDenom = () => {
299
- let denom = { ...config }
300
- updateConfig({ ...config, customDenom: !denom.customDenom })
301
- }
200
+ const editorContent = (
201
+
202
+ <Accordion>
203
+ <Accordion.Section title="General">
204
+ <InputText value={config.title} fieldName="title" label="Title" placeholder="Waffle Chart Title"
205
+ updateField={updateField}/>
206
+ <InputText type="textarea" value={config.content} fieldName="content" label="Message" updateField={updateField} tooltip={
207
+ <Tooltip style={{textTransform: 'none'}}>
208
+ <Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
209
+ <Tooltip.Content>
210
+ <p>Enter the message text for the visualization. The following HTML tags are supported: strong, em, sup, and sub.</p>
211
+ </Tooltip.Content>
212
+ </Tooltip>
213
+ }/>
214
+ <InputText value={config.subtext} fieldName="subtext" label="Subtext/Citation"
215
+ placeholder="Waffle Chart Subtext or Citation" updateField={updateField} tooltip={
216
+ <Tooltip style={{textTransform: 'none'}}>
217
+ <Tooltip.Target><Icon display="question" style={{marginLeft: '0.5rem'}}/></Tooltip.Target>
218
+ <Tooltip.Content>
219
+ <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
220
+ </Tooltip.Content>
221
+ </Tooltip>
222
+ }/>
223
+ </Accordion.Section>
224
+ <Accordion.Section title="Data">
225
+ <h4 style={{ fontWeight: '600' }}>Numerator</h4>
226
+ <div className="cove-accordion__panel-section">
227
+ <div className="cove-input-group">
228
+ <InputSelect value={config.dataColumn || ''} fieldName="dataColumn" label="Data Column"
229
+ updateField={updateField} initial="Select" options={getColumns()}/>
230
+ </div>
231
+
232
+ <div className="cove-input-group">
233
+ <InputSelect value={config.dataFunction || ''} fieldName="dataFunction" label="Data Function"
234
+ updateField={updateField} initial="Select" options={DATA_FUNCTIONS}/>
235
+ </div>
236
+
237
+ <div className="cove-input-group">
238
+ <label><span className="edit-label">Data Conditional</span></label>
239
+ <div className="cove-accordion__panel-row cove-accordion__small-inputs">
240
+ <div className="cove-accordion__panel-col">
241
+ <InputSelect value={config.dataConditionalColumn || ''} fieldName="dataConditionalColumn"
242
+ updateField={updateField} initial="Select" options={getColumns()}/>
243
+ </div>
244
+ <div className="cove-accordion__panel-col">
245
+ <InputSelect value={config.dataConditionalOperator || ''} fieldName="dataConditionalOperator"
246
+ updateField={updateField} initial="Select" options={DATA_OPERATORS}/>
247
+ </div>
248
+ <div className="cove-accordion__panel-col">
249
+ <InputText value={config.dataConditionalComparate} fieldName={'dataConditionalComparate'}
250
+ updateField={updateField}
251
+ className={config.invalidComparate ? 'cove-accordion__input-error' : ''}
252
+ style={{minHeight: '2rem'}}
253
+ />
254
+ </div>
255
+ </div>
256
+ </div>
257
+
258
+ {config.invalidComparate &&
259
+ <div className="cove-accordion__panel-error">
260
+ Non-numerical comparate values can only be used with = or ≠.
261
+ </div>
262
+ }
263
+ </div>
264
+ <div className="cove-accordion__panel-row align-center">
265
+ <div className="cove-accordion__panel-col">
266
+ <h4 style={{ fontWeight: '600' }}>Denominator</h4>
267
+ </div>
268
+ <div className="cove-accordion__panel-col">
269
+ <div style={{display: 'flex', justifyContent: 'flex-end'}}>
270
+ <label className="cove-accordion__panel-label--inline">Select from data</label>
271
+ <InputCheckbox size='small' value={config.customDenom} fieldName='customDenom' updateField={updateField}/>
272
+ </div>
273
+ </div>
274
+ </div>
275
+ <div className="cove-accordion__panel-section">
276
+ {!config.customDenom &&
277
+ <div className="cove-accordion__panel-row align-center">
278
+ <div className="cove-accordion__panel-col">
279
+ <InputText value={config.dataDenom} fieldName="dataDenom" updateField={updateField}/>
280
+ </div>
281
+ <div className="cove-accordion__panel-col" style={{display: 'flex', alignItems: 'center'}}>
282
+ <label className="cove-accordion__panel-label--muted">default (100)</label>
283
+ </div>
284
+ </div>
285
+ }
286
+ {config.customDenom &&
287
+ <>
288
+ <InputSelect value={config.dataDenomColumn || ''} fieldName="dataDenomColumn" label="Data Column"
289
+ updateField={updateField} initial="Select" options={getColumns()}/>
290
+ <InputSelect value={config.dataDenomFunction || ''} fieldName="dataDenomFunction" label="Data Function"
291
+ updateField={updateField} initial="Select" options={DATA_FUNCTIONS}/>
292
+ </>
293
+ }
294
+ </div>
295
+ <ul className="column-edit">
296
+ <li className="three-col">
297
+ <div style={{marginRight: '1rem'}}>
298
+ <InputText value={config.prefix} fieldName="prefix" label="Prefix" updateField={updateField}/>
299
+ </div>
300
+ <div style={{marginRight: '1rem'}}>
301
+ <InputText value={config.suffix} fieldName="suffix" label="Suffix" updateField={updateField}/>
302
+ </div>
303
+ <div>
304
+ <InputText type="number" value={config.roundToPlace} fieldName="roundToPlace" label="Round" updateField={updateField}/>
305
+ </div>
306
+ </li>
307
+ </ul>
308
+
309
+ <hr className="cove-accordion__divider" />
310
+
311
+ <label style={{marginBottom: '1rem'}}>
312
+ <span className="edit-label">Data Point Filters</span>
313
+ <Tooltip style={{ textTransform: 'none' }}>
314
+ <Tooltip.Target><Icon display="question" style={{ marginLeft: '0.5rem' }}/></Tooltip.Target>
315
+ <Tooltip.Content>
316
+ <p>To refine the highlighted data point, specify one or more filters (e.g., "Male" and
317
+ "Female" for a column called "Sex").</p>
318
+ </Tooltip.Content>
319
+ </Tooltip>
320
+ </label>
321
+ {config.filters &&
322
+ <ul className="filters-list" style={{paddingLeft: 0, marginBottom: '1rem'}}>
323
+ {config.filters.map((filter, index) => (
324
+ <fieldset className="edit-block" key={index}>
325
+ <button type="button" className="remove-column" onClick={() => {
326
+ removeFilter(index)
327
+ }}>Remove
328
+ </button>
329
+ <label>
330
+ <span className="edit-label column-heading">Column</span>
331
+ <select value={filter.columnName} onChange={(e) => {
332
+ updateFilterProp('columnName', index, e.target.value)
333
+ }}>
334
+ <option value="">- Select Option -</option>
335
+ {getColumns().map((dataKey, index) => (
336
+ <option value={dataKey} key={index}>{dataKey}</option>
337
+ ))}
338
+ </select>
339
+ </label>
340
+ <label>
341
+ <span className="edit-label column-heading">Column Value</span>
342
+ <select value={filter.columnValue} onChange={(e) => {
343
+ updateFilterProp('columnValue', index, e.target.value)
344
+ }}>
345
+ <option value="">- Select Option -</option>
346
+ {getFilterColumnValues(index).map((dataKey, index) => (
347
+ <option value={dataKey} key={index}>{dataKey}</option>
348
+ ))}
349
+ </select>
350
+ </label>
351
+ </fieldset>
352
+ ))}
353
+ </ul>
354
+ }
355
+ <Button onClick={addNewFilter} fluid>Add Filter</Button>
356
+ </Accordion.Section>
357
+ <Accordion.Section title="Visual">
358
+ <InputSelect value={config.shape} fieldName="shape" label="Shape"
359
+ updateField={updateField} options={[ 'circle', 'square', 'person' ]}/>
360
+
361
+ <div className="cove-accordion__panel-row cove-accordion__small-inputs" style={{marginTop: '1rem', marginBottom: '1rem'}}>
362
+ <div className="cove-accordion__panel-col">
363
+ <InputText type="number" value={config.nodeWidth} fieldName="nodeWidth" label="Width" updateField={updateField}/>
364
+ </div>
365
+ <div className="cove-accordion__panel-col">
366
+ <InputText type="number" value={config.nodeSpacer} fieldName="nodeSpacer" label="Spacer" updateField={updateField}/>
367
+ </div>
368
+ </div>
369
+
370
+ <div className="cove-input-group">
371
+ <InputSelect value={config.orientation} fieldName="orientation" label="Layout"
372
+ updateField={updateField} options={[ 'horizontal', 'vertical' ]}/>
373
+ </div>
374
+
375
+ <div className="cove-input-group">
376
+ <label><span className="edit-label column-heading">Data Point Font Size</span></label>
377
+ <div className="cove-accordion__panel-row cove-accordion__small-inputs align-center">
378
+ <div className="cove-accordion__panel-col">
379
+ <InputText type="number" value={config.fontSize} fieldName="fontSize" updateField={updateField}/>
380
+ </div>
381
+ <div className="cove-accordion__panel-col" style={{display: 'flex', alignItems: 'center'}}>
382
+ <label className="accordion__panel-label--muted">default (50px)</label>
383
+ </div>
384
+ </div>
385
+ </div>
386
+
387
+ <InputSelect value={config.overallFontSize} fieldName="overallFontSize" label="Overall Font Size"
388
+ updateField={updateField} options={[ 'small', 'medium', 'large' ]}/>
389
+
390
+ <label>
391
+ <span className="edit-label">Theme</span>
392
+ <ul className="color-palette">
393
+ {headerColors.map((palette) => (
394
+ <li title={palette} key={palette} onClick={() => {
395
+ updateConfig({ ...config, theme: palette })
396
+ }} className={config.theme === palette ? 'selected ' + palette : palette}>
397
+ </li>
398
+ ))}
399
+ </ul>
400
+
401
+ {/* <div className="cove-accordion__panel-section">
402
+ <CheckBox value={config.visual.border} section="visual" fieldName="border" label="Display Borders" updateField={updateField} />
403
+ <CheckBox value={config.visual.borderColorTheme} section="visual" fieldName="borderColorTheme" label="Use theme border color" updateField={updateField} />
404
+ <CheckBox value={config.visual.accent} section="visual" fieldName="accent" label="Use Accent Style" updateField={updateField} />
405
+ <CheckBox value={config.visual.background} section="visual" fieldName="background" label="Use theme background color" updateField={updateField} />
406
+ <CheckBox value={config.visual.hideBackgroundColor} section="visual" fieldName="hideBackgroundColor" label="Hide Background Color" updateField={updateField} />
407
+ </div> */}
408
+
409
+ </label>
410
+ </Accordion.Section>
411
+ </Accordion>
412
+ )
302
413
 
303
- if (loading) {
304
- return null
305
- }
414
+ if (loading) return null
306
415
 
307
416
  return (
308
417
  <ErrorBoundary component="EditorPanel">
309
- {!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error/>}
310
- {config.newViz && <Confirm/>}
311
- <button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`}
312
- title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick}/>
313
- <section className={displayPanel ? 'editor-panel' : 'hidden editor-panel'}>
314
- <h2>Configure Waffle Chart</h2>
315
- <section className="form-container">
316
- <form>
317
- <Accordion allowZeroExpanded={true}>
318
- <AccordionItem> {/* General */}
319
- <AccordionItemHeading>
320
- <AccordionItemButton>
321
- General
322
- </AccordionItemButton>
323
- </AccordionItemHeading>
324
- <AccordionItemPanel>
325
- <TextField value={config.title} fieldName="title" label="Title" placeholder="Waffle Chart Title"
326
- updateField={updateField}/>
327
- <TextField type="textarea" value={config.content} fieldName="content" label="Message"
328
- updateField={updateField}/>
329
- <TextField value={config.subtext} fieldName="subtext" label="Subtext/Citation"
330
- placeholder="Waffle Chart Subtext or Citation" updateField={updateField}/>
331
- </AccordionItemPanel>
332
- </AccordionItem>
333
- <AccordionItem>
334
- <AccordionItemHeading>
335
- <AccordionItemButton>
336
- Data
337
- </AccordionItemButton>
338
- </AccordionItemHeading>
339
- <AccordionItemPanel>
340
- <h4 style={{ fontWeight: '600' }}>Numerator</h4>
341
- <div className="accordion__panel-section">
342
- <Select value={config.dataColumn || ''} fieldName="dataColumn" label="Data Column"
343
- updateField={updateField} initial="Select" options={getColumns()}/>
344
- <Select value={config.dataFunction || ''} fieldName="dataFunction" label="Data Function"
345
- updateField={updateField} initial="Select" options={DATA_FUNCTIONS}/>
346
- <label><span className="edit-label">Data Conditional</span></label>
347
- <div className="accordion__panel-row accordion__small-inputs">
348
- <div className="accordion__panel-col">
349
- <Select value={config.dataConditionalColumn || ''} fieldName="dataConditionalColumn"
350
- updateField={updateField} initial="Select" options={getColumns()}/>
351
- </div>
352
- <div className="accordion__panel-col">
353
- <Select value={config.dataConditionalOperator || ''} fieldName="dataConditionalOperator"
354
- updateField={updateField} initial="Select" options={DATA_OPERATORS}/>
355
- </div>
356
- <div className="accordion__panel-col">
357
- <TextField value={config.dataConditionalComparate} fieldName={'dataConditionalComparate'}
358
- updateField={updateField}
359
- className={config.invalidComparate ? 'accordion__input-error' : ''}/>
360
- </div>
361
- </div>
362
- {config.invalidComparate &&
363
- <div className="accordion__panel-error">Non-numerical comparate values can only be used with = or
364
- ≠.</div>
365
- }
366
- </div>
367
-
368
- <div className="accordion__panel-row align-center">
369
- <div className="accordion__panel-col">
370
- <h4 style={{ fontWeight: '600' }}>Denominator</h4>
371
- </div>
372
- <div className="accordion__panel-col">
373
- <div className="d-flex justify-end">
374
- <label className={'accordion__panel-label--inline'}>Select from data</label>
375
- <div className={`accordion__panel-checkbox${config.customDenom ? ' checked' : ''}`}
376
- onClick={() => toggleCustomDenom()}/>
377
- </div>
378
- </div>
379
- </div>
380
- <div className="accordion__panel-section">
381
- {!config.customDenom &&
382
- <div className="accordion__panel-row align-center">
383
- <div className="accordion__panel-col">
384
- <TextField value={config.dataDenom} fieldName="dataDenom" updateField={updateField}/>
385
- </div>
386
- <div className="accordion__panel-col">
387
- <label className={'accordion__panel-label--muted'}>default (100)</label>
388
- </div>
389
- </div>
390
- }
391
- {config.customDenom &&
392
- <>
393
- <Select value={config.dataDenomColumn || ''} fieldName="dataDenomColumn" label="Data Column"
394
- updateField={updateField} initial="Select" options={getColumns()}/>
395
- <Select value={config.dataDenomFunction || ''} fieldName="dataDenomFunction" label="Data Function"
396
- updateField={updateField} initial="Select" options={DATA_FUNCTIONS}/>
397
- </>
398
- }
399
- </div>
400
- <ul className="column-edit">
401
- <li className="three-col">
402
- <TextField value={config.prefix} fieldName="prefix" label="Prefix" updateField={updateField}/>
403
- <TextField value={config.suffix} fieldName="suffix" label="Suffix" updateField={updateField}/>
404
- <TextField type="number" value={config.roundToPlace} fieldName="roundToPlace" label="Round"
405
- updateField={updateField}/>
406
- </li>
407
- </ul>
408
- </AccordionItemPanel>
409
- </AccordionItem>
410
- <AccordionItem>
411
- <AccordionItemHeading>
412
- <AccordionItemButton>
413
- Filters
414
- </AccordionItemButton>
415
- </AccordionItemHeading>
416
- <AccordionItemPanel>
417
- <ul className="filters-list">
418
- {config.filters && config.filters.map((filter, index) => (
419
- <fieldset className="edit-block" key={index}>
420
- <button type="button" className="remove-column" onClick={() => {
421
- removeFilter(index)
422
- }}>Remove
423
- </button>
424
- <label>
425
- <span className="edit-label column-heading">Column</span>
426
- <select value={filter.columnName} onChange={(e) => {
427
- updateFilterProp('columnName', index, e.target.value)
428
- }}>
429
- <option value="">- Select Option -</option>
430
- {getColumns().map((dataKey, index) => (
431
- <option value={dataKey} key={index}>{dataKey}</option>
432
- ))}
433
- </select>
434
- </label>
435
- <label>
436
- <span className="edit-label column-heading">Column Value</span>
437
- <select value={filter.columnValue} onChange={(e) => {
438
- updateFilterProp('columnValue', index, e.target.value)
439
- }}>
440
- <option value="">- Select Option -</option>
441
- {getFilterColumnValues(index).map((dataKey, index) => (
442
- <option value={dataKey} key={index}>{dataKey}</option>
443
- ))}
444
- </select>
445
- </label>
446
- </fieldset>
447
- )
448
- )}
449
- </ul>
450
-
451
- <button type="button" onClick={addNewFilter} className="btn btn-primary">Add Filter</button>
452
- </AccordionItemPanel>
453
- </AccordionItem>
454
- <AccordionItem>
455
- <AccordionItemHeading>
456
- <AccordionItemButton>
457
- Visual
458
- </AccordionItemButton>
459
- </AccordionItemHeading>
460
- <AccordionItemPanel>
461
- <Select value={config.shape} fieldName="shape" label="Shape"
462
- updateField={updateField} options={[ 'circle', 'square', 'person' ]}/>
463
-
464
- <div className="accordion__panel-row accordion__small-inputs" style={{marginTop: '1em'}}>
465
- <div className="accordion__panel-col">
466
- <TextField type="number" value={config.nodeWidth} fieldName="nodeWidth" label="Width" updateField={updateField}/>
467
- </div>
468
- <div className="accordion__panel-col">
469
- <TextField type="number" value={config.nodeSpacer} fieldName="nodeSpacer" label="Spacer" updateField={updateField}/>
470
- </div>
471
- </div>
472
-
473
- <Select value={config.orientation} fieldName="orientation" label="Layout"
474
- updateField={updateField} options={[ 'horizontal', 'vertical' ]}/>
475
-
476
- <label><span className="edit-label column-heading">Data Point Font Size</span></label>
477
- <div className="accordion__panel-row accordion__small-inputs align-center">
478
- <div className="accordion__panel-col">
479
- <TextField type="number" value={config.fontSize} fieldName="fontSize" updateField={updateField}/>
480
- </div>
481
- <div className="accordion__panel-col">
482
- <label className={'accordion__panel-label--muted'}>default (50px)</label>
483
- </div>
484
- </div>
485
-
486
- <Select value={config.overallFontSize} fieldName="overallFontSize" label="Overall Font Size"
487
- updateField={updateField} options={[ 'small', 'medium', 'large' ]}/>
488
-
489
- <label className="header">
490
- <span className="edit-label">Theme</span>
491
- <ul className="color-palette">
492
- {headerColors.map((palette) => (
493
- <li title={palette} key={palette} onClick={() => {
494
- updateConfig({ ...config, theme: palette })
495
- }} className={config.theme === palette ? 'selected ' + palette : palette}>
496
- </li>
497
- ))}
498
- </ul>
499
- </label>
500
- </AccordionItemPanel>
501
- </AccordionItem>
502
- </Accordion>
503
- </form>
418
+ <div className="cove-editor">
419
+ {!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error/>}
420
+ {config.newViz && showConfigConfirm && <Confirm/>}
421
+ <button className={`cove-editor--toggle` + (!displayPanel ? ` collapsed` : ``)}
422
+ title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick}/>
423
+ <section className={`cove-editor__panel` + (displayPanel ? `` : ' hidden')}>
424
+ <div className="cove-editor__panel-container">
425
+ <h2 className="cove-editor__heading">Configure Waffle Chart</h2>
426
+ <section className="cove-editor__content">
427
+ {editorContent}
428
+ </section>
429
+ </div>
504
430
  </section>
505
- </section>
431
+ <div className="cove-editor__content">
432
+ <div className="cove-editor__content-wrap">
433
+ {props.children}
434
+ </div>
435
+ </div>
436
+ </div>
506
437
  </ErrorBoundary>
507
438
  )
508
439
  })