@cdc/core 4.25.11 → 4.26.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.
Files changed (147) hide show
  1. package/.claude/agents/qa-test-developer.md +126 -0
  2. package/CLAUDE.local.md +67 -0
  3. package/_stories/Gallery.Charts.stories.tsx +300 -0
  4. package/_stories/Gallery.DataBite.stories.tsx +79 -0
  5. package/_stories/Gallery.Maps.stories.tsx +239 -0
  6. package/_stories/Gallery.WaffleChart.stories.tsx +187 -0
  7. package/_stories/PageART.stories.tsx +193 -0
  8. package/_stories/PageBRFSS.stories.tsx +294 -0
  9. package/_stories/PageCancerRegistries.stories.tsx +199 -0
  10. package/_stories/PageEasternEquineEncephalitis.stories.tsx +216 -0
  11. package/_stories/PageExcessiveAlcoholUse.stories.tsx +201 -0
  12. package/_stories/PageMaternalMortality.stories.tsx +193 -0
  13. package/_stories/PageOralHealth.stories.tsx +201 -0
  14. package/_stories/PageRespiratory.stories.tsx +332 -0
  15. package/_stories/PageSmokingTobacco.stories.tsx +200 -0
  16. package/_stories/PageStateDiabetesProfiles.stories.tsx +201 -0
  17. package/_stories/PageWastewater.stories.tsx +477 -0
  18. package/_stories/VegaImport.stories.tsx +401 -0
  19. package/_stories/vega-fixtures/bars-with-line.json +444 -0
  20. package/_stories/vega-fixtures/bars.json +58 -0
  21. package/_stories/vega-fixtures/combo-bar-rolling-mean.json +88 -0
  22. package/_stories/vega-fixtures/combo.json +68 -0
  23. package/_stories/vega-fixtures/grouped-horizontal-bars.json +83 -0
  24. package/_stories/vega-fixtures/grouped-horizontal-bars2.json +231 -0
  25. package/_stories/vega-fixtures/horizontal-bar.json +427 -0
  26. package/_stories/vega-fixtures/horizontal-bars-with-bad-colors.json +197 -0
  27. package/_stories/vega-fixtures/horizontal-bars2.json +58 -0
  28. package/_stories/vega-fixtures/lines.json +227 -0
  29. package/_stories/vega-fixtures/measles-bars.json +348 -0
  30. package/_stories/vega-fixtures/measles-map.json +11101 -0
  31. package/_stories/vega-fixtures/measles-stacked-bars.json +2147 -0
  32. package/_stories/vega-fixtures/multi-dataset.json +255 -0
  33. package/_stories/vega-fixtures/no-data.json +14 -0
  34. package/_stories/vega-fixtures/pie-chart.json +94 -0
  35. package/_stories/vega-fixtures/repeat-spec.json +47 -0
  36. package/_stories/vega-fixtures/stacked-area.json +222 -0
  37. package/_stories/vega-fixtures/stacked-bar-with-rect.json +3412 -0
  38. package/_stories/vega-fixtures/stacked-bars-with-line.json +364 -0
  39. package/_stories/vega-fixtures/stacked-bars.json +212 -0
  40. package/_stories/vega-fixtures/stacked-horizontal-bars.json +140 -0
  41. package/_stories/vega-fixtures/warning-combo.json +59 -0
  42. package/_stories/vega-fixtures/warning-scatter-and-line.json +1182 -0
  43. package/assets/icon-chart-area.svg +1 -0
  44. package/assets/icon-chart-radar.svg +23 -0
  45. package/assets/icon-magnifying-glass.svg +5 -0
  46. package/assets/icon-warming-stripes.svg +13 -0
  47. package/assets/logo2.svg +31 -0
  48. package/components/AdvancedEditor/AdvancedEditor.tsx +4 -0
  49. package/components/AdvancedEditor/EmbedEditor.tsx +513 -0
  50. package/components/ComboBox/ComboBox.tsx +345 -0
  51. package/components/ComboBox/combobox.styles.css +185 -0
  52. package/components/ComboBox/index.ts +1 -0
  53. package/components/CustomColorsEditor/CustomColorsEditor.tsx +3 -10
  54. package/components/DataTable/DataTable.tsx +132 -58
  55. package/components/DataTable/data-table.css +216 -215
  56. package/components/DataTable/helpers/getSeriesName.ts +6 -0
  57. package/components/DataTable/helpers/mapCellMatrix.tsx +14 -6
  58. package/components/EditorPanel/ColumnsEditor.tsx +37 -19
  59. package/components/EditorPanel/DataTableEditor.tsx +51 -25
  60. package/components/EditorPanel/EditorPanel.styles.css +16 -0
  61. package/components/EditorPanel/EditorPanel.tsx +144 -0
  62. package/components/EditorPanel/EditorPanelDispatch.tsx +75 -0
  63. package/components/EditorPanel/FieldSetWrapper.tsx +66 -23
  64. package/components/EditorPanel/Inputs.tsx +33 -7
  65. package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +14 -6
  66. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +240 -175
  67. package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +33 -29
  68. package/components/EditorPanel/sections/VisualSection.tsx +169 -0
  69. package/components/Filters/Filters.tsx +31 -5
  70. package/components/Filters/helpers/getNestedOptions.ts +2 -1
  71. package/components/Filters/helpers/handleSorting.ts +1 -1
  72. package/components/Layout/components/Sidebar/components/sidebar.styles.scss +84 -2
  73. package/components/Layout/components/Visualization/index.tsx +27 -1
  74. package/components/Layout/components/Visualization/visualizations.scss +7 -0
  75. package/components/Legend/Legend.Gradient.tsx +1 -1
  76. package/components/MediaControls.tsx +53 -28
  77. package/components/_stories/CustomColorsEditor.stories.tsx +37 -0
  78. package/components/_stories/DataTable.stories.tsx +1 -0
  79. package/components/ui/Icon.tsx +3 -1
  80. package/components/ui/Title/index.tsx +30 -2
  81. package/components/ui/Title/title.styles.css +42 -0
  82. package/data/colorPalettes.ts +18 -5
  83. package/data/mapColorPalettes.ts +10 -0
  84. package/devTemplate/dev.js +235 -0
  85. package/devTemplate/index.html +30 -0
  86. package/devTemplate/preview.html +1503 -0
  87. package/devTemplate/sidebar.css +151 -0
  88. package/dist/cove-main.css +2803 -4448
  89. package/dist/cove-main.css.map +1 -1
  90. package/generateViteConfig.js +118 -2
  91. package/helpers/DataTransform.ts +1 -5
  92. package/helpers/addValuesToFilters.ts +6 -1
  93. package/helpers/cove/date.ts +33 -1
  94. package/helpers/cove/string.ts +29 -0
  95. package/helpers/coveUpdateWorker.ts +21 -12
  96. package/helpers/embed/embedCodeGenerator.ts +80 -0
  97. package/helpers/embed/embedHelper.js +158 -0
  98. package/helpers/embed/filterUtils.ts +121 -0
  99. package/helpers/embed/index.ts +21 -0
  100. package/helpers/embed/urlValidation.ts +119 -0
  101. package/helpers/filterVizData.ts +6 -1
  102. package/helpers/getFileExtension.ts +0 -6
  103. package/helpers/getUniqueValues.ts +19 -0
  104. package/helpers/hashObj.ts +25 -0
  105. package/helpers/isRightAlignedTableValue.js +5 -0
  106. package/helpers/metrics/helpers.ts +1 -0
  107. package/helpers/metrics/types.ts +3 -0
  108. package/helpers/palettes/colorDistributions.ts +1 -1
  109. package/helpers/palettes/utils.ts +12 -12
  110. package/helpers/parseCsvWithQuotes.ts +15 -14
  111. package/helpers/pivotData.ts +2 -2
  112. package/helpers/prepareScreenshot.ts +288 -0
  113. package/helpers/queryStringUtils.ts +29 -0
  114. package/helpers/testing.ts +44 -0
  115. package/helpers/tests/DataTransform.test.ts +125 -0
  116. package/helpers/tests/date.test.ts +64 -0
  117. package/helpers/tests/prepareScreenshot.test.ts +414 -0
  118. package/helpers/tests/queryStringUtils.test.ts +381 -0
  119. package/helpers/tests/testStandaloneBuild.ts +23 -5
  120. package/helpers/useDataVizClasses.ts +0 -1
  121. package/helpers/vegaConfig.ts +1 -1
  122. package/helpers/vegaConfigImport.ts +160 -0
  123. package/helpers/ver/4.26.1.ts +80 -0
  124. package/helpers/ver/4.26.2.ts +84 -0
  125. package/helpers/ver/tests/4.26.1.test.ts +105 -0
  126. package/helpers/ver/tests/4.26.2.test.ts +298 -0
  127. package/helpers/viewports.ts +2 -0
  128. package/hooks/useDataColumns.ts +63 -0
  129. package/hooks/useFilterManagement.ts +94 -0
  130. package/hooks/useLegendSeparators.ts +26 -0
  131. package/hooks/useListManagement.ts +192 -0
  132. package/package.json +29 -33
  133. package/styles/_button-section.scss +0 -3
  134. package/styles/v2/components/editor.scss +9 -9
  135. package/styles/v2/utils/_grid.scss +8 -3
  136. package/types/Annotation.ts +10 -11
  137. package/types/Axis.ts +1 -0
  138. package/types/ForecastingSeriesKey.ts +1 -0
  139. package/types/General.ts +2 -0
  140. package/types/MarkupInclude.ts +1 -0
  141. package/types/Palette.ts +21 -0
  142. package/types/Series.ts +3 -0
  143. package/types/Table.ts +1 -0
  144. package/types/Visualization.ts +7 -0
  145. package/types/VizFilter.ts +1 -0
  146. package/LICENSE +0 -201
  147. package/_stories/StoryRenderingTests.stories.tsx +0 -164
@@ -14,6 +14,7 @@ import FilterOrder from './components/FilterOrder'
14
14
  import { useMemo, useState } from 'react'
15
15
  import MultiSelect from '../../MultiSelect'
16
16
  import NestedDropdownEditor from './NestedDropdownEditor'
17
+ import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
17
18
 
18
19
  type VizFilterProps = {
19
20
  config: Visualization
@@ -24,6 +25,7 @@ type VizFilterProps = {
24
25
 
25
26
  const VizFilterEditor: React.FC<VizFilterProps> = ({ config, updateField, rawData, hasFootnotes }) => {
26
27
  const openControls = useState({})
28
+ const [isNestedDragHovered, setIsNestedDragHovered] = useState(false)
27
29
  const dataColumns = useMemo(() => {
28
30
  return _.uniq(_.flatten(rawData?.map(row => Object.keys(row))))
29
31
  }, [rawData])
@@ -128,6 +130,26 @@ const VizFilterEditor: React.FC<VizFilterProps> = ({ config, updateField, rawDat
128
130
  .map(({ label, columnName, id }) => ({ label: label || columnName, value: id }))
129
131
  }
130
132
 
133
+ const handleFilterReorder = (idx1: number, idx2: number) => {
134
+ if (idx1 === undefined || idx2 === undefined || idx1 === idx2) return
135
+ const filters = _.cloneDeep(config.filters)
136
+ const [movedFilter] = filters.splice(idx1, 1)
137
+ filters.splice(idx2, 0, movedFilter)
138
+ updateField(null, null, 'filters', filters)
139
+ }
140
+
141
+ const getItemStyle = (isDragging: boolean, draggableStyle: any) => ({
142
+ ...draggableStyle
143
+ })
144
+
145
+ const sortableItemStyles = {
146
+ animate: false,
147
+ animateReplay: true,
148
+ display: 'block',
149
+ boxSizing: 'border-box' as const,
150
+ border: '1px solid #D1D1D1'
151
+ }
152
+
131
153
  return (
132
154
  <>
133
155
  {config.filters && (
@@ -160,188 +182,231 @@ const VizFilterEditor: React.FC<VizFilterProps> = ({ config, updateField, rawDat
160
182
  fieldName='filterIntro'
161
183
  />
162
184
  <br />
163
- <ul className='filters-list'>
164
- {/* Whether filters should apply onChange or Apply Button */}
185
+ <DragDropContext
186
+ onDragEnd={({ source, destination }) => handleFilterReorder(source.index, destination?.index)}
187
+ >
188
+ <Droppable droppableId='filters_list'>
189
+ {provided => (
190
+ <ul {...provided.droppableProps} ref={provided.innerRef} className='draggable-field-list'>
191
+ {/* Whether filters should apply onChange or Apply Button */}
165
192
 
166
- {config.filters.map((filter, filterIndex) => {
167
- if (filter.type === 'url') return <></>
168
- return (
169
- <FieldSetWrapper
170
- key={filter.columnName}
171
- fieldName={filter.columnName}
172
- fieldKey={filterIndex}
173
- fieldType='Filter'
174
- controls={openControls}
175
- deleteField={() => removeFilter(filterIndex)}
176
- >
177
- <Select
178
- value={filter.filterStyle}
179
- fieldName='filterStyle'
180
- label='Filter Style'
181
- updateField={(_section, _subsection, _field, value) => updateFilterStyle(filterIndex, value)}
182
- options={filterStyleOptions}
183
- />
193
+ {config.filters.map((filter, filterIndex) => {
194
+ if (filter.type === 'url') return <></>
195
+ return (
196
+ <Draggable
197
+ key={filter.id || `filter-${filterIndex}`}
198
+ draggableId={`filter-${filter.id || filterIndex}`}
199
+ index={filterIndex}
200
+ isDragDisabled={isNestedDragHovered}
201
+ >
202
+ {(provided, snapshot) => (
203
+ <div
204
+ ref={provided.innerRef}
205
+ {...provided.draggableProps}
206
+ {...provided.dragHandleProps}
207
+ className={snapshot.isDragging ? 'currently-dragging' : ''}
208
+ style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
209
+ >
210
+ <FieldSetWrapper
211
+ key={filter.columnName}
212
+ fieldName={filter.columnName}
213
+ fieldKey={filterIndex}
214
+ fieldType='Filter'
215
+ controls={openControls}
216
+ deleteField={() => removeFilter(filterIndex)}
217
+ draggable={true}
218
+ >
219
+ <Select
220
+ value={filter.filterStyle}
221
+ fieldName='filterStyle'
222
+ label='Filter Style'
223
+ updateField={(_section, _subsection, _field, value) =>
224
+ updateFilterStyle(filterIndex, value)
225
+ }
226
+ options={filterStyleOptions}
227
+ />
184
228
 
185
- {filter.filterStyle !== 'nested-dropdown' ? (
186
- <>
187
- <Select
188
- value={filter.columnName}
189
- fieldName='columnName'
190
- label='Filter'
191
- updateField={(_section, _subsection, _field, value) => handleNameChange(filterIndex, value)}
192
- options={dataColumns}
193
- initial='- Select Option -'
194
- />
229
+ {filter.filterStyle !== 'nested-dropdown' ? (
230
+ <>
231
+ <Select
232
+ value={filter.columnName}
233
+ fieldName='columnName'
234
+ label='Filter'
235
+ updateField={(_section, _subsection, _field, value) =>
236
+ handleNameChange(filterIndex, value)
237
+ }
238
+ options={dataColumns}
239
+ initial='- Select Option -'
240
+ />
195
241
 
196
- {filter.columnName && (
197
- <Select
198
- value={filter.defaultValue}
199
- options={
200
- filter.resetLabel
201
- ? [filter.resetLabel, ...getFilterValues(filter)]
202
- : getFilterValues(filter)
203
- }
204
- updateField={(_section, _subSection, _key, value) => {
205
- updateFilterDefaultValue(filterIndex, value)
206
- }}
207
- label='Filter Default Value'
208
- initial='Select'
209
- />
210
- )}
242
+ {filter.columnName && (
243
+ <Select
244
+ value={filter.defaultValue}
245
+ options={
246
+ filter.resetLabel
247
+ ? [filter.resetLabel, ...getFilterValues(filter)]
248
+ : getFilterValues(filter)
249
+ }
250
+ updateField={(_section, _subSection, _key, value) => {
251
+ updateFilterDefaultValue(filterIndex, value)
252
+ }}
253
+ label={`Filter Default Value${
254
+ filter.columnName ? ` (${filter.columnName})` : ''
255
+ }`}
256
+ initial='Select'
257
+ />
258
+ )}
211
259
 
212
- <label>
213
- <span className='edit-label column-heading'>Label</span>
214
- <input
215
- type='text'
216
- value={filter.label}
217
- onChange={e => {
218
- updateFilterProp('label', filterIndex, e.target.value)
219
- }}
220
- />
221
- </label>
260
+ <label>
261
+ <span className='edit-label column-heading'>Label</span>
262
+ <input
263
+ type='text'
264
+ value={filter.label}
265
+ onChange={e => {
266
+ updateFilterProp('label', filterIndex, e.target.value)
267
+ }}
268
+ />
269
+ </label>
222
270
 
223
- {filter.filterStyle === 'multi-select' && (
224
- <TextField
225
- label='Select Limit'
226
- value={(filter as MultiSelectFilter).selectLimit}
227
- updateField={updateField}
228
- section='filters'
229
- subsection={filterIndex}
230
- fieldName='selectLimit'
231
- type='number'
232
- tooltip={
233
- <Tooltip style={{ textTransform: 'none' }}>
234
- <Tooltip.Target>
235
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
236
- </Tooltip.Target>
237
- <Tooltip.Content>
238
- <p>The maximum number of items that can be selected.</p>
239
- </Tooltip.Content>
240
- </Tooltip>
241
- }
242
- />
243
- )}
271
+ {filter.filterStyle === 'multi-select' && (
272
+ <TextField
273
+ label='Select Limit'
274
+ value={(filter as MultiSelectFilter).selectLimit}
275
+ updateField={updateField}
276
+ section='filters'
277
+ subsection={filterIndex}
278
+ fieldName='selectLimit'
279
+ type='number'
280
+ tooltip={
281
+ <Tooltip style={{ textTransform: 'none' }}>
282
+ <Tooltip.Target>
283
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
284
+ </Tooltip.Target>
285
+ <Tooltip.Content>
286
+ <p>The maximum number of items that can be selected.</p>
287
+ </Tooltip.Content>
288
+ </Tooltip>
289
+ }
290
+ />
291
+ )}
244
292
 
245
- <Select
246
- value={filter.order || 'asc'}
247
- fieldName='order'
248
- label='Filter Order'
249
- updateField={(_section, _subSection, _field, value) => {
250
- updateFilterProp('order', filterIndex, value)
251
- if (filter.orderColumn && value !== 'column') updateFilterProp('orderColumn', filterIndex, '')
252
- }}
253
- options={filterOrderOptions}
254
- />
255
- {filter.order === 'cust' && (
256
- <FilterOrder
257
- orderedValues={filter.orderedValues || filter.values}
258
- handleFilterOrder={(index1, index2) => handleFilterOrder(index1, index2, filterIndex)}
259
- />
260
- )}
261
- {filter.order === 'column' && (
262
- <Select
263
- value={filter.orderColumn}
264
- fieldName='orderColumn'
265
- label='Order Column'
266
- updateField={(_section, _subSection, _field, value) =>
267
- updateFilterProp('orderColumn', filterIndex, value)
268
- }
269
- options={dataColumns}
270
- />
271
- )}
272
- <label>
273
- <span className='edit-label column-heading'>Default Value Set By Query String Parameter</span>
274
- <input
275
- type='text'
276
- value={filter.setByQueryParameter}
277
- onChange={e => {
278
- updateFilterProp('setByQueryParameter', filterIndex, e.target.value)
279
- }}
280
- />
281
- </label>
293
+ <Select
294
+ value={filter.order || 'asc'}
295
+ fieldName='order'
296
+ label='Filter Order'
297
+ updateField={(_section, _subSection, _field, value) => {
298
+ updateFilterProp('order', filterIndex, value)
299
+ if (filter.orderColumn && value !== 'column')
300
+ updateFilterProp('orderColumn', filterIndex, '')
301
+ }}
302
+ options={filterOrderOptions}
303
+ />
304
+ {filter.order === 'cust' && (
305
+ <FilterOrder
306
+ orderedValues={filter.orderedValues || filter.values}
307
+ handleFilterOrder={(index1, index2) =>
308
+ handleFilterOrder(index1, index2, filterIndex)
309
+ }
310
+ onNestedDragAreaHover={setIsNestedDragHovered}
311
+ />
312
+ )}
313
+ {filter.order === 'column' && (
314
+ <Select
315
+ value={filter.orderColumn}
316
+ fieldName='orderColumn'
317
+ label='Order Column'
318
+ updateField={(_section, _subSection, _field, value) =>
319
+ updateFilterProp('orderColumn', filterIndex, value)
320
+ }
321
+ options={dataColumns}
322
+ />
323
+ )}
324
+ <label>
325
+ <span className='edit-label column-heading'>
326
+ Default Value Set By Query String Parameter
327
+ </span>
328
+ <input
329
+ type='text'
330
+ value={filter.setByQueryParameter}
331
+ onChange={e => {
332
+ updateFilterProp('setByQueryParameter', filterIndex, e.target.value)
333
+ }}
334
+ />
335
+ </label>
282
336
 
283
- <label>
284
- <input
285
- type='checkbox'
286
- checked={filter.showDropdown === undefined ? true : filter.showDropdown}
287
- onChange={e => {
288
- updateFilterProp('showDropdown', filterIndex, e.target.checked)
289
- }}
290
- />
291
- <span className='edit-showDropdown column-heading'>Show Filter</span>
292
- </label>
293
- </>
294
- ) : (
295
- <NestedDropdownEditor
296
- config={config}
297
- dataColumns={dataColumns}
298
- filterIndex={filterIndex}
299
- rawData={rawData}
300
- handleGroupingCustomOrder={(index1, index2) => handleFilterOrder(index1, index2, filterIndex)}
301
- handleNameChange={value => handleNameChange(filterIndex, value)}
302
- updateField={updateField}
303
- updateFilterStyle={updateFilterStyle}
304
- />
305
- )}
306
- {hasFootnotes && (
307
- <label>
308
- <input
309
- type='checkbox'
310
- checked={!!filter.filterFootnotes}
311
- onChange={e => {
312
- updateFilterProp('filterFootnotes', filterIndex, e.target.checked)
313
- }}
314
- />
315
- <span className='edit-showDropdown column-heading'>Filter Footnotes</span>
316
- </label>
317
- )}
318
- <label>
319
- <span className='edit-label column-heading'>
320
- Filter Parents{' '}
321
- <Tooltip style={{ textTransform: 'none' }}>
322
- <Tooltip.Target>
323
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
324
- </Tooltip.Target>
325
- <Tooltip.Content>
326
- <p>
327
- A selected parent's value will be used to filter the available options of this child filter.
328
- </p>
329
- </Tooltip.Content>
330
- </Tooltip>
331
- </span>
332
- <MultiSelect
333
- fieldName='parents'
334
- updateField={(_section, _subsection, _fieldname, value) => {
335
- updateFilterProp('parents', filterIndex, value)
336
- }}
337
- options={getParentFilterOptions(filterIndex)}
338
- selected={config.filters[filterIndex].parents}
339
- />
340
- </label>
341
- </FieldSetWrapper>
342
- )
343
- })}
344
- </ul>
337
+ <label>
338
+ <input
339
+ type='checkbox'
340
+ checked={filter.showDropdown === undefined ? true : filter.showDropdown}
341
+ onChange={e => {
342
+ updateFilterProp('showDropdown', filterIndex, e.target.checked)
343
+ }}
344
+ />
345
+ <span className='edit-showDropdown column-heading'>Show Filter</span>
346
+ </label>
347
+ </>
348
+ ) : (
349
+ <NestedDropdownEditor
350
+ config={config}
351
+ dataColumns={dataColumns}
352
+ filterIndex={filterIndex}
353
+ rawData={rawData}
354
+ handleGroupingCustomOrder={(index1, index2) =>
355
+ handleFilterOrder(index1, index2, filterIndex)
356
+ }
357
+ handleNameChange={value => handleNameChange(filterIndex, value)}
358
+ updateField={updateField}
359
+ updateFilterStyle={updateFilterStyle}
360
+ onNestedDragAreaHover={setIsNestedDragHovered}
361
+ />
362
+ )}
363
+ {hasFootnotes && (
364
+ <label>
365
+ <input
366
+ type='checkbox'
367
+ checked={!!filter.filterFootnotes}
368
+ onChange={e => {
369
+ updateFilterProp('filterFootnotes', filterIndex, e.target.checked)
370
+ }}
371
+ />
372
+ <span className='edit-showDropdown column-heading'>Filter Footnotes</span>
373
+ </label>
374
+ )}
375
+ <label>
376
+ <span className='edit-label column-heading'>
377
+ Filter Parents{' '}
378
+ <Tooltip style={{ textTransform: 'none' }}>
379
+ <Tooltip.Target>
380
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
381
+ </Tooltip.Target>
382
+ <Tooltip.Content>
383
+ <p>
384
+ A selected parent's value will be used to filter the available options of this
385
+ child filter.
386
+ </p>
387
+ </Tooltip.Content>
388
+ </Tooltip>
389
+ </span>
390
+ <MultiSelect
391
+ fieldName='parents'
392
+ updateField={(_section, _subsection, _fieldname, value) => {
393
+ updateFilterProp('parents', filterIndex, value)
394
+ }}
395
+ options={getParentFilterOptions(filterIndex)}
396
+ selected={config.filters[filterIndex].parents}
397
+ />
398
+ </label>
399
+ </FieldSetWrapper>
400
+ </div>
401
+ )}
402
+ </Draggable>
403
+ )
404
+ })}
405
+ {provided.placeholder}
406
+ </ul>
407
+ )}
408
+ </Droppable>
409
+ </DragDropContext>
345
410
  </>
346
411
  )}
347
412
  {!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
@@ -3,37 +3,41 @@ import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
3
3
  type FilterOrderProps = {
4
4
  orderedValues: string[]
5
5
  handleFilterOrder?: (index1: number, index2: number) => void
6
+ onNestedDragAreaHover?: (isHovering: boolean) => void
6
7
  }
7
- const FilterOrder: React.FC<FilterOrderProps> = ({ orderedValues, handleFilterOrder }) => {
8
+
9
+ const FilterOrder: React.FC<FilterOrderProps> = ({ orderedValues, handleFilterOrder, onNestedDragAreaHover }) => {
8
10
  return (
9
- <DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source?.index, destination?.index)}>
10
- <Droppable droppableId='filter_order'>
11
- {provided => (
12
- <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
13
- {orderedValues?.map((value, index) => {
14
- return (
15
- <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
16
- {(provided, snapshot) => (
17
- <li>
18
- <div
19
- className={snapshot.isDragging ? 'currently-dragging' : ''}
20
- style={provided.draggableProps.style}
21
- ref={provided.innerRef}
22
- {...provided.draggableProps}
23
- {...provided.dragHandleProps}
24
- >
25
- {value}
26
- </div>
27
- </li>
28
- )}
29
- </Draggable>
30
- )
31
- })}
32
- {provided.placeholder}
33
- </ul>
34
- )}
35
- </Droppable>
36
- </DragDropContext>
11
+ <div onMouseEnter={() => onNestedDragAreaHover?.(true)} onMouseLeave={() => onNestedDragAreaHover?.(false)}>
12
+ <DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source?.index, destination?.index)}>
13
+ <Droppable droppableId='filter_order'>
14
+ {provided => (
15
+ <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
16
+ {orderedValues?.map((value, index) => {
17
+ return (
18
+ <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
19
+ {(provided, snapshot) => (
20
+ <li>
21
+ <div
22
+ className={snapshot.isDragging ? 'currently-dragging' : ''}
23
+ style={provided.draggableProps.style}
24
+ ref={provided.innerRef}
25
+ {...provided.draggableProps}
26
+ {...provided.dragHandleProps}
27
+ >
28
+ {value}
29
+ </div>
30
+ </li>
31
+ )}
32
+ </Draggable>
33
+ )
34
+ })}
35
+ {provided.placeholder}
36
+ </ul>
37
+ )}
38
+ </Droppable>
39
+ </DragDropContext>
40
+ </div>
37
41
  )
38
42
  }
39
43