@cdc/core 4.25.8 → 4.25.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.
Files changed (163) hide show
  1. package/_stories/StoryRenderingTests.stories.tsx +164 -0
  2. package/components/AdvancedEditor/AdvancedEditor.tsx +32 -9
  3. package/components/CustomColorsEditor/CustomColorsEditor.css +299 -0
  4. package/components/CustomColorsEditor/CustomColorsEditor.tsx +209 -0
  5. package/components/CustomColorsEditor/index.ts +1 -0
  6. package/components/DataTable/DataTable.tsx +56 -38
  7. package/components/DataTable/DataTableStandAlone.tsx +8 -3
  8. package/components/DataTable/components/ChartHeader.tsx +44 -14
  9. package/components/DataTable/components/DataTableEditorPanel.tsx +12 -2
  10. package/components/DataTable/components/ExpandCollapse.tsx +10 -1
  11. package/components/DataTable/components/MapHeader.tsx +24 -13
  12. package/components/DataTable/data-table.css +12 -0
  13. package/components/DataTable/helpers/chartCellMatrix.tsx +11 -8
  14. package/components/DataTable/helpers/mapCellMatrix.tsx +33 -4
  15. package/components/DataTable/helpers/standardizeState.js +2 -2
  16. package/components/DataTable/helpers/tests/standardizeState.test.js +54 -0
  17. package/components/DownloadButton.tsx +40 -14
  18. package/components/EditorPanel/DataTableEditor.tsx +3 -3
  19. package/components/EditorPanel/EditorPanel.styles.css +423 -0
  20. package/components/EditorPanel/FootnotesEditor.tsx +44 -37
  21. package/components/EditorPanel/Inputs.tsx +12 -2
  22. package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +35 -62
  23. package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +12 -2
  24. package/components/EditorPanel/components/MarkupHighlightedTextField.tsx +227 -0
  25. package/components/EditorPanel/components/MarkupVariablesEditor.tsx +450 -0
  26. package/components/EditorPanel/components/PanelMarkup.tsx +59 -0
  27. package/components/ErrorBoundary.jsx +3 -1
  28. package/components/Filters/Filters.tsx +52 -24
  29. package/components/Filters/components/Dropdown.tsx +6 -1
  30. package/components/Filters/components/Tabs.tsx +1 -0
  31. package/components/Footnotes/Footnotes.tsx +35 -25
  32. package/components/Footnotes/FootnotesStandAlone.tsx +42 -6
  33. package/components/HeaderThemeSelector/HeaderThemeSelector.css +43 -0
  34. package/components/HeaderThemeSelector/HeaderThemeSelector.stories.tsx +74 -0
  35. package/components/HeaderThemeSelector/HeaderThemeSelector.tsx +61 -0
  36. package/components/HeaderThemeSelector/index.ts +2 -0
  37. package/components/Layout/styles/editor.scss +2 -1
  38. package/components/Legend/Legend.Gradient.tsx +3 -6
  39. package/components/LegendShape.tsx +121 -3
  40. package/components/Loader/Loader.tsx +1 -1
  41. package/components/MediaControls.tsx +72 -21
  42. package/components/PaletteConversionModal.tsx +90 -0
  43. package/components/PaletteSelector/DeveloperPaletteRollback.tsx +114 -0
  44. package/components/PaletteSelector/PaletteSelector.css +94 -0
  45. package/components/PaletteSelector/PaletteSelector.tsx +112 -0
  46. package/components/PaletteSelector/index.ts +2 -0
  47. package/components/RichTooltip/RichTooltip.tsx +1 -0
  48. package/components/Table/Table.tsx +3 -1
  49. package/components/Table/components/Cell.tsx +23 -2
  50. package/components/Table/components/Row.tsx +5 -3
  51. package/components/_stories/BlurStrokeTest.stories.tsx +1 -1
  52. package/components/_stories/DataTable.stories.tsx +1 -1
  53. package/components/_stories/Filters.stories.tsx +21 -2
  54. package/components/_stories/Footnotes.CSV.stories.tsx +247 -0
  55. package/components/_stories/Footnotes.stories.tsx +769 -4
  56. package/components/_stories/Inputs.stories.tsx +3 -3
  57. package/components/_stories/MultiSelect.stories.tsx +3 -3
  58. package/components/_stories/NestedDropdown.stories.tsx +1 -1
  59. package/components/_stories/Table.stories.tsx +1 -1
  60. package/components/_stories/styles.scss +0 -1
  61. package/components/elements/_stories/Button.stories.tsx +1 -1
  62. package/components/elements/_stories/Card.stories.tsx +1 -1
  63. package/components/inputs/InputToggle.tsx +2 -0
  64. package/components/managers/DataDesigner.tsx +10 -9
  65. package/components/managers/_stories/DataDesigner.stories.tsx +1 -1
  66. package/components/ui/Accordion.jsx +1 -1
  67. package/components/ui/Tooltip.tsx +2 -1
  68. package/components/ui/_stories/Accordion.stories.tsx +1 -1
  69. package/components/ui/_stories/ColorPaletteMigration.stories.mdx +275 -0
  70. package/components/ui/_stories/Colors.stories.tsx +330 -0
  71. package/components/ui/_stories/IconGallery.stories.tsx +316 -0
  72. package/components/ui/_stories/Title.stories.tsx +1 -1
  73. package/components/ui/accordion.styles.css +57 -0
  74. package/contexts/EditorContext.ts +18 -0
  75. package/contexts/editor.actions.ts +28 -0
  76. package/contexts/editor.reducer.ts +94 -0
  77. package/data/chartColorPalettes.ts +118 -0
  78. package/data/colorPalettes.ts +9 -0
  79. package/data/mapColorPalettes.ts +45 -0
  80. package/data/sharedPalettes.ts +50 -0
  81. package/dist/cove-main.css +63 -14
  82. package/dist/cove-main.css.map +1 -1
  83. package/generateViteConfig.js +80 -0
  84. package/helpers/addValuesToFilters.ts +7 -3
  85. package/helpers/cloneConfig.ts +31 -0
  86. package/helpers/configDataHelpers.ts +128 -0
  87. package/helpers/configHelpers.ts +27 -0
  88. package/helpers/constants.ts +42 -2
  89. package/helpers/cove/number.ts +33 -12
  90. package/helpers/coveUpdateWorker.ts +15 -3
  91. package/helpers/fetchRemoteData.ts +3 -15
  92. package/helpers/filterColorPalettes.ts +152 -0
  93. package/helpers/generateColorsArray.ts +13 -0
  94. package/helpers/getColorPaletteVersion.ts +33 -0
  95. package/helpers/getPaletteAccessor.ts +18 -0
  96. package/helpers/markupProcessor.ts +220 -0
  97. package/helpers/mergeCustomOrderValues.ts +37 -0
  98. package/helpers/metrics/helpers.ts +42 -19
  99. package/helpers/metrics/types.ts +48 -9
  100. package/helpers/metrics/utils.ts +34 -0
  101. package/helpers/palettes/colorDistributions.ts +56 -0
  102. package/helpers/palettes/migratePaletteName.ts +150 -0
  103. package/helpers/palettes/standardizePaletteNames.ts +77 -0
  104. package/helpers/palettes/utils.ts +267 -0
  105. package/helpers/parseCsvWithQuotes.ts +65 -0
  106. package/helpers/queryStringUtils.ts +13 -0
  107. package/helpers/testing.ts +358 -0
  108. package/helpers/tests/addValuesToFilters.test.ts +1 -2
  109. package/helpers/tests/generateColorsArray.test.ts +24 -0
  110. package/helpers/tests/markupProcessor.test.ts +538 -0
  111. package/helpers/tests/testStandaloneBuild.ts +44 -0
  112. package/helpers/useMarkupVariables.ts +31 -0
  113. package/helpers/vegaConfig.ts +0 -1
  114. package/helpers/ver/4.24.10.ts +2 -1
  115. package/helpers/ver/4.24.11.ts +2 -1
  116. package/helpers/ver/4.24.3.ts +2 -1
  117. package/helpers/ver/4.24.4.ts +2 -1
  118. package/helpers/ver/4.24.5.ts +2 -1
  119. package/helpers/ver/4.24.7.ts +2 -1
  120. package/helpers/ver/4.24.9.ts +2 -1
  121. package/helpers/ver/4.25.1.ts +2 -1
  122. package/helpers/ver/4.25.10.ts +36 -0
  123. package/helpers/ver/4.25.11.ts +13 -0
  124. package/helpers/ver/4.25.3.ts +2 -1
  125. package/helpers/ver/4.25.4.ts +2 -1
  126. package/helpers/ver/4.25.6.ts +2 -1
  127. package/helpers/ver/4.25.7.ts +2 -1
  128. package/helpers/ver/4.25.8.ts +2 -1
  129. package/helpers/ver/4.25.9.ts +293 -0
  130. package/helpers/ver/tests/4.25.10.test.ts +204 -0
  131. package/helpers/ver/tests/4.25.8.test.ts +1 -1
  132. package/helpers/ver/tests/4.25.9.test.ts +51 -0
  133. package/helpers/viewports.ts +2 -0
  134. package/hooks/useColorPalette.ts +79 -0
  135. package/package.json +13 -4
  136. package/styles/_common-components.css +73 -0
  137. package/styles/_global.scss +32 -10
  138. package/styles/base.scss +8 -55
  139. package/styles/cove-main.scss +3 -1
  140. package/styles/filters.scss +10 -3
  141. package/styles/v2/base/index.scss +0 -1
  142. package/styles/v2/components/button.scss +4 -3
  143. package/styles/v2/components/editor.scss +16 -7
  144. package/styles/v2/layout/_data-table.scss +3 -2
  145. package/styles/v2/themes/_color-definitions.scss +18 -17
  146. package/styles/v2/utils/_breakpoints.scss +1 -1
  147. package/styles/v2/utils/index.scss +0 -1
  148. package/styles/waiting.scss +1 -1
  149. package/testing-setup.js +32 -0
  150. package/types/MarkupInclude.ts +8 -2
  151. package/types/MarkupVariable.ts +19 -0
  152. package/types/VizFilter.ts +2 -0
  153. package/vitest.config.ts +16 -0
  154. package/components/ui/_stories/Colors.stories.mdx +0 -220
  155. package/components/ui/_stories/IconGallery.stories.mdx +0 -14
  156. package/data/colorPalettes.js +0 -171
  157. package/helpers/formatConfigBeforeSave.ts +0 -135
  158. package/helpers/tests/formatConfigBeforeSave.test.ts +0 -68
  159. package/styles/_mixins.scss +0 -13
  160. package/styles/v2/base/_typography.scss +0 -0
  161. package/styles/v2/components/guidance-block.scss +0 -74
  162. package/styles/v2/utils/_functions.scss +0 -0
  163. /package/{styles/_typography.scss → testBuild.js} +0 -0
@@ -0,0 +1,56 @@
1
+ // Chart color distributions for v2 9-color sequential palettes to improve contrast
2
+ // Similar to map distributions but optimized for chart legends
3
+ export const v2ColorDistribution = {
4
+ 1: [4], // Middle color for single item
5
+ 2: [0, 8], // First and middle
6
+ 3: [0, 4, 8], // First, middle, last
7
+ 4: [0, 2, 6, 8], // Evenly spaced
8
+ 5: [0, 2, 4, 6, 8], // Well-distributed
9
+ 6: [0, 1, 3, 5, 7, 8], // Good spacing
10
+ 7: [0, 1, 2, 4, 6, 7, 8], // Skip middle-adjacent
11
+ 8: [0, 1, 2, 3, 5, 6, 7, 8], // Skip one in middle
12
+ 9: [0, 1, 2, 3, 4, 5, 6, 7, 8] // Use all colors
13
+ }
14
+
15
+ // Enhanced color distributions for divergent palettes to maximize contrast
16
+ // Prioritizes endpoints and avoids the neutral middle region
17
+ export const divergentColorDistribution = {
18
+ 1: [4], // Neutral middle for single item
19
+ 2: [1, 7], // Strong contrast from each end
20
+ 3: [0, 4, 8], // Maximum endpoints plus neutral
21
+ 4: [0, 2, 6, 8], // Well-spaced with emphasis on extremes
22
+ 5: [0, 1, 4, 7, 8], // Skip adjacent to middle, emphasize ends
23
+ 6: [0, 1, 3, 5, 7, 8], // Avoid immediate middle area
24
+ 7: [0, 1, 2, 4, 6, 7, 8], // Skip one middle-adjacent
25
+ 8: [0, 1, 2, 3, 5, 6, 7, 8], // Skip one in middle
26
+ 9: [0, 1, 2, 3, 4, 5, 6, 7, 8] // Use all colors
27
+ }
28
+
29
+ // Color distribution optimized for colorblind-safe palette accessibility
30
+ // Maximizes perceptual differences for color vision deficiency
31
+ export const colorblindColorDistribution = {
32
+ 1: [0], // Start with strongest color
33
+ 2: [0, 4], // High contrast pair (orange, blue)
34
+ 3: [0, 2, 4], // Orange, green, blue - maximum differentiation
35
+ 4: [0, 1, 2, 4], // Add cyan for more separation
36
+ 5: [0, 1, 2, 4, 5], // Add dark blue for depth
37
+ 6: [0, 1, 2, 4, 5, 6], // Add pink for additional distinction
38
+ 7: [0, 1, 2, 4, 5, 6, 8], // Add brown, skip black temporarily
39
+ 8: [0, 1, 2, 4, 5, 6, 7, 8], // Add black for maximum contrast
40
+ 9: [0, 1, 2, 3, 4, 5, 6, 7, 8] // Use all colors
41
+ }
42
+
43
+ // Basic color distribution for map v1 compatibility
44
+ // Simple distribution pattern for any palette length up to 10 items
45
+ export const mapV1ColorDistribution = {
46
+ 1: [1],
47
+ 2: [1, 3],
48
+ 3: [1, 3, 5],
49
+ 4: [0, 2, 4, 6],
50
+ 5: [0, 2, 4, 6, 7],
51
+ 6: [0, 2, 3, 4, 5, 7],
52
+ 7: [0, 2, 3, 4, 5, 6, 7],
53
+ 8: [0, 2, 3, 4, 5, 6, 7, 8],
54
+ 9: [0, 1, 2, 3, 4, 5, 6, 7, 8],
55
+ 10: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
56
+ }
@@ -0,0 +1,150 @@
1
+ // Chart palette migration map
2
+ export const chartPaletteMigrationMap: Record<string, string> = {
3
+ yelloworangered: 'sequential_orange',
4
+ yelloworangebrown: 'sequential_orange',
5
+ orangered: 'sequential_orange',
6
+ yellowpurple: 'sequential_orange',
7
+ red: 'sequential_orange',
8
+ 'Sequential Orange': 'sequential_orange',
9
+ 'Sequential Orange Two': 'sequential_orange',
10
+ 'sequential-orange(MPX)': 'sequential_orange',
11
+ 'sequential-orange-(MPX)': 'sequential_orange',
12
+ pinkpurple: 'sequential_purple',
13
+ bluegreen: 'sequential_blue',
14
+ 'sequential-blue': 'sequential_blue',
15
+ 'sequential-blue-2-(MPX)': 'sequential_blue',
16
+ 'sequential-blue-2(MPX)': 'sequential_blue',
17
+ 'Sequential Blue': 'sequential_blue',
18
+ 'sequential Blue Two': 'sequential_blue',
19
+ 'sequential Blue Three': 'sequential_blue',
20
+ greenblue: 'sequential_green',
21
+ 'Sequential Green': 'sequential_green',
22
+ qualitative1: 'qualitative_standard',
23
+ qualitative2: 'qualitative_standard',
24
+ qualitative3: 'qualitative_standard',
25
+ qualitative4: 'qualitative_standard',
26
+ colorblindsafe: 'qualitative_standard',
27
+ 'qualitative-bold': 'qualitative_standard',
28
+ 'qualitative-soft': 'qualitative_standard',
29
+ // Reverse palette migrations
30
+ yelloworangeredreverse: 'sequential_orangereverse',
31
+ yelloworangebrownreverse: 'sequential_orangereverse',
32
+ orangeredreverse: 'sequential_orangereverse',
33
+ yellowpurplereverse: 'sequential_orangereverse',
34
+ redreverse: 'sequential_orangereverse',
35
+ 'Sequential Orangereverse': 'sequential_orangereverse',
36
+ 'Sequential Orange Tworeverse': 'sequential_orangereverse',
37
+ 'sequential-orange(MPX)reverse': 'sequential_orangereverse',
38
+ 'sequential-orange-(MPX)reverse': 'sequential_orangereverse',
39
+ pinkpurplereverse: 'sequential_purplereverse',
40
+ bluegreenreverse: 'sequential_bluereverse',
41
+ 'sequential-bluereverse': 'sequential_bluereverse',
42
+ 'sequential-blue-2-(MPX)reverse': 'sequential_bluereverse',
43
+ 'sequential-blue-2(MPX)reverse': 'sequential_bluereverse',
44
+ 'Sequential Bluereverse': 'sequential_bluereverse',
45
+ 'sequential Blue Tworeverse': 'sequential_bluereverse',
46
+ 'sequential Blue Threereverse': 'sequential_bluereverse',
47
+ greenbluereverse: 'sequential_greenreverse',
48
+ 'Sequential Greenreverse': 'sequential_greenreverse',
49
+ qualitative1reverse: 'qualitative_standardreverse',
50
+ qualitative2reverse: 'qualitative_standardreverse',
51
+ qualitative3reverse: 'qualitative_standardreverse',
52
+ qualitative4reverse: 'qualitative_standardreverse',
53
+ colorblindsafereverse: 'qualitative_standardreverse',
54
+ 'qualitative-boldreverse': 'qualitative_standardreverse',
55
+ 'qualitative-softreverse': 'qualitative_standardreverse'
56
+ }
57
+
58
+ // Map palette migration map
59
+ export const mapPaletteMigrationMap: Record<string, string> = {
60
+ sequential_yellow_orange_red: 'sequential_orange',
61
+ sequential_yellow_orange_brown: 'sequential_orange',
62
+ sequential_orange_red: 'sequential_orange',
63
+ sequential_orange_extended: 'sequential_orange',
64
+ sequential_pink_purple: 'sequential_purple',
65
+ divergent_yellow_purple: 'divergent_blue_purple',
66
+ sequential_blue_green: 'sequential_blue',
67
+ sequential_blue_extended: 'sequential_blue',
68
+ sequential_green_blue: 'sequential_teal',
69
+ sequential_red: 'sequential_orange',
70
+ qualitative_earth_tones: 'qualitative',
71
+ // Reverse palette migrations
72
+ sequential_yellow_orange_redreverse: 'sequential_orangereverse',
73
+ sequential_yellow_orange_brownreverse: 'sequential_orangereverse',
74
+ sequential_orange_redreverse: 'sequential_orangereverse',
75
+ sequential_orange_extendedreverse: 'sequential_orangereverse',
76
+ sequential_pink_purplereverse: 'sequential_purplereverse',
77
+ divergent_yellow_purplereverse: 'divergent_blue_purplereverse',
78
+ sequential_blue_greenreverse: 'sequential_bluereverse',
79
+ sequential_blue_extendedreverse: 'sequential_bluereverse',
80
+ sequential_green_bluereverse: 'sequential_tealreverse',
81
+ sequential_redreverse: 'sequential_orangereverse',
82
+ qualitative_earth_tonesreverse: 'qualitativereverse',
83
+ 'qualitative_bold': 'qualitative_standard',
84
+ 'qualitative_soft': 'qualitative_standard',
85
+ 'qualitative_boldreverse': 'qualitative_standardreverse',
86
+ 'qualitative_softreverse': 'qualitative_standardreverse',
87
+ 'qualitative1': 'qualitative_standard',
88
+ 'qualitative2': 'qualitative_standard',
89
+ 'qualitative3': 'qualitative_standard',
90
+ 'qualitative4': 'qualitative_standard',
91
+ 'colorblindsafe': 'qualitative_standard',
92
+ 'qualitative1reverse': 'qualitative_standardreverse',
93
+ 'qualitative2reverse': 'qualitative_standardreverse',
94
+ 'qualitative3reverse': 'qualitative_standardreverse',
95
+ 'qualitative4reverse': 'qualitative_standardreverse',
96
+ }
97
+
98
+ // Two-color palette migration map (v1 to v2)
99
+ export const twoColorPaletteMigrationMap: Record<string, string> = {
100
+ // Monochrome palettes → divergent_blue_purple
101
+ 'monochrome-1': 'divergent_blue_purple',
102
+ 'monochrome-2': 'divergent_blue_purple',
103
+ 'monochrome-3': 'divergent_blue_purple',
104
+ 'monochrome-4': 'divergent_blue_purple',
105
+
106
+ // Warm palettes → divergent_green_orange
107
+ 'monochrome-5': 'divergent_green_orange',
108
+ 'warm-1': 'divergent_green_orange',
109
+
110
+ // Cool palettes → divergent_blue_cyan
111
+ 'cool-1': 'divergent_blue_cyan',
112
+ 'cool-2': 'divergent_blue_cyan',
113
+ 'cool-3': 'divergent_blue_cyan',
114
+ 'cool-4': 'divergent_blue_cyan',
115
+ 'cool-5': 'divergent_blue_cyan',
116
+
117
+ // Complementary palettes → divergent_blue_orange
118
+ 'complementary-1': 'divergent_blue_orange',
119
+ 'complementary-2': 'divergent_blue_orange',
120
+ 'complementary-3': 'divergent_blue_orange',
121
+ 'complementary-4': 'divergent_blue_orange',
122
+ 'complementary-5': 'divergent_blue_orange',
123
+
124
+ // Reverse palette migrations
125
+ 'monochrome-1reverse': 'divergent_blue_purplereverse',
126
+ 'monochrome-2reverse': 'divergent_blue_purplereverse',
127
+ 'monochrome-3reverse': 'divergent_blue_purplereverse',
128
+ 'monochrome-4reverse': 'divergent_blue_purplereverse',
129
+ 'monochrome-5reverse': 'divergent_green_orangereverse',
130
+ 'warm-1reverse': 'divergent_green_orangereverse',
131
+ 'cool-1reverse': 'divergent_blue_cyanreverse',
132
+ 'cool-2reverse': 'divergent_blue_cyanreverse',
133
+ 'cool-3reverse': 'divergent_blue_cyanreverse',
134
+ 'cool-4reverse': 'divergent_blue_cyanreverse',
135
+ 'cool-5reverse': 'divergent_blue_cyanreverse',
136
+ 'complementary-1reverse': 'divergent_blue_orangereverse',
137
+ 'complementary-2reverse': 'divergent_blue_orangereverse',
138
+ 'complementary-3reverse': 'divergent_blue_orangereverse',
139
+ 'complementary-4reverse': 'divergent_blue_orangereverse',
140
+ 'complementary-5reverse': 'divergent_blue_orangereverse'
141
+ }
142
+
143
+ // Combined palette migration map for backward compatibility
144
+ export const paletteMigrationMap: Record<string, string> = {
145
+ ...chartPaletteMigrationMap,
146
+ ...mapPaletteMigrationMap,
147
+ ...twoColorPaletteMigrationMap
148
+ }
149
+
150
+
@@ -0,0 +1,77 @@
1
+ // Rename Palettes
2
+ export const newMapPaletteNames = {
3
+ 'yelloworangered': 'sequential_yellow_orange_red',
4
+ 'yelloworangebrown': 'sequential_yellow_orange_brown',
5
+ 'yelloworangebrownreverse': 'sequential_yellow_orange_brownreverse',
6
+ 'pinkpurple': 'sequential_pink_purple',
7
+ 'pinkpurplereverse': 'sequential_pink_purplereverse',
8
+ 'bluegreen': 'sequential_blue_green',
9
+ 'bluegreenreverse': 'sequential_blue_greenreverse',
10
+ 'orangered': 'sequential_orange_red',
11
+ 'orangeredreverse': 'sequential_orange_redreverse',
12
+ 'red': 'sequential_red',
13
+ 'redreverse': 'sequential_red_reverse',
14
+ 'greenblue': 'sequential_green_blue',
15
+ 'greenbluereverse': 'sequential_green_bluereverse',
16
+ 'yelloworangeredreverse': 'sequential_yellow_orange_redreverse',
17
+ 'yellowpurple': 'divergent_yellow_purple',
18
+ 'yellowpurplereverse': 'divergent_yellow_purplereverse',
19
+ 'qualitative1': 'qualitative1',
20
+ 'qualitative2': 'qualitative2',
21
+ 'qualitative3': 'qualitative3',
22
+ 'qualitative4': 'qualitative4',
23
+ 'qualitative9': 'qualitative9',
24
+ 'sequential-blue-2(MPX)': 'sequential_blue_extended',
25
+ 'sequential-blue-2(MPX)reverse': 'sequential_blue_extendedreverse',
26
+ 'sequential-orange(MPX)': 'sequential_orange_extended',
27
+ 'sequential-orange(MPX)reverse': 'sequential_orange_extendedreverse',
28
+ 'colorblindsafe': 'colorblindsafe',
29
+ 'qualitative1reverse': 'qualitative1reverse',
30
+ 'qualitative2reverse': 'qualitative2reverse',
31
+ 'qualitative3reverse': 'qualitative3reverse',
32
+ 'qualitative4reverse': 'qualitative4reverse',
33
+ 'qualitative9reverse': 'qualitative9reverse',
34
+ 'colorblindsafereverse': 'colorblindsafereverse',
35
+ }
36
+
37
+ export const newChartPaletteNames = {
38
+ 'qualitative-bold': 'qualitative_bold',
39
+ 'qualitative-soft': 'qualitative_soft',
40
+ 'qualitative-standard': 'qualitative_standard',
41
+ 'sequential-blue': 'sequential_blue',
42
+ 'sequential-blue-2-(MPX)': 'sequential_blue_extended',
43
+ 'sequential-orange': 'sequential_orange',
44
+ 'sequential-orange-(MPX)': 'sequential_orange_extended',
45
+ 'sequential-green': 'sequential_green',
46
+ 'sequential-purple': 'sequential_purple',
47
+ 'sequential-teal': 'sequential_teal',
48
+ 'divergent-bluecyan': 'divergent_blue_cyan',
49
+ 'divergent-bluepurple': 'divergent_blue_purple',
50
+ 'divergent-greenorange': 'divergent_green_orange',
51
+ 'divergent-blueorange': 'divergent_blue_orange',
52
+ 'qualitative1': 'qualitative1',
53
+ 'qualitative2': 'qualitative2',
54
+ 'qualitative3': 'qualitative3',
55
+ 'qualitative4': 'qualitative4',
56
+ 'colorblindsafe': 'colorblindsafe',
57
+ // Reverse variants
58
+ 'qualitative-boldreverse': 'qualitative_boldreverse',
59
+ 'qualitative-softreverse': 'qualitative_softreverse',
60
+ 'qualitative-standardreverse': 'qualitative_standardreverse',
61
+ 'sequential-bluereverse': 'sequential_bluereverse',
62
+ 'sequential-blue-2-(MPX)reverse': 'sequential_blue_extendedreverse',
63
+ 'sequential-orangereverse': 'sequential_orangereverse',
64
+ 'sequential-orange-(MPX)reverse': 'sequential_orange_extendedreverse',
65
+ 'sequential-greenreverse': 'sequential_greenreverse',
66
+ 'sequential-purplereverse': 'sequential_purplereverse',
67
+ 'sequential-tealreverse': 'sequential_tealreverse',
68
+ 'divergent-bluecyanreverse': 'divergent_blue_cyanreverse',
69
+ 'divergent-bluepurplereverse': 'divergent_blue_purplereverse',
70
+ 'divergent-greenorangereverse': 'divergent_green_orangereverse',
71
+ 'divergent-blueorangereverse': 'divergent_blue_orangereverse',
72
+ 'qualitative1reverse': 'qualitative1reverse',
73
+ 'qualitative2reverse': 'qualitative2reverse',
74
+ 'qualitative3reverse': 'qualitative3reverse',
75
+ 'qualitative4reverse': 'qualitative4reverse',
76
+ 'colorblindsafereverse': 'colorblindsafereverse'
77
+ }
@@ -0,0 +1,267 @@
1
+ import { map } from 'lodash'
2
+ import { FALLBACK_COLOR_PALETTE_V1, FALLBACK_COLOR_PALETTE_V2, USE_V2_MIGRATION } from '../constants'
3
+ import { getColorPaletteVersion } from '../getColorPaletteVersion'
4
+ import { getPaletteAccessor } from '../getPaletteAccessor'
5
+ import { chartPaletteMigrationMap } from './migratePaletteName'
6
+ import { newMapPaletteNames } from './standardizePaletteNames'
7
+
8
+ /**
9
+ * Gets the current palette name from a visualization config
10
+ * @param config - The visualization config object
11
+ * @returns The current palette name or empty string if not found
12
+ */
13
+ export const getCurrentPaletteName = (config: any): string => {
14
+ // Check new v2 format first
15
+ if (config?.general?.palette?.name) {
16
+ return config.general.palette.name
17
+ }
18
+
19
+ // Check legacy v1 formats
20
+ if (config?.palette) {
21
+ return config.palette
22
+ }
23
+
24
+ if (config?.color) {
25
+ return config.color
26
+ }
27
+
28
+ const paletteVersion = getColorPaletteVersion(config)
29
+ return paletteVersion === 1 ? FALLBACK_COLOR_PALETTE_V1 : FALLBACK_COLOR_PALETTE_V2
30
+ }
31
+
32
+ /**
33
+ * Gets the palette colors array from a visualization config
34
+ * @param config - The visualization config object
35
+ * @param colorPalettes - The color palettes object (e.g., mapColorPalettes, chartColorPalettes)
36
+ * @returns The palette colors array or empty array if not found
37
+ */
38
+ export const getPaletteColors = (config: any, colorPalettes: any): string[] => {
39
+ // First check for custom colors (v2 format)
40
+ if (config?.general?.palette?.customColors) {
41
+ return config.general.palette.customColors
42
+ }
43
+
44
+ // Get the raw palette name
45
+ let paletteName = getCurrentPaletteName(config)
46
+
47
+ // Apply v1 palette name migrations if this is a v1 config
48
+ const paletteVersion = getColorPaletteVersion(config)
49
+ if (paletteVersion === 1) {
50
+ paletteName = migratePaletteWithMap(paletteName, chartPaletteMigrationMap, true)
51
+ }
52
+
53
+ // Get the versioned palette accessor
54
+ const versionedPalettes = getPaletteAccessor(colorPalettes, config)
55
+
56
+ if (paletteName && versionedPalettes?.[paletteName]) {
57
+ return versionedPalettes[paletteName]
58
+ }
59
+
60
+ return []
61
+ }
62
+
63
+ /**
64
+ * Determines if the config is using a v1 palette configuration
65
+ * @param config - The visualization config object
66
+ * @returns True if the config is using v1 palette configuration (which would show conversion modal)
67
+ */
68
+ export const isV1Palette = (config: any): boolean => {
69
+ // If v2 migration is disabled globally, don't treat as v1 (no conversion modal)
70
+ if (!USE_V2_MIGRATION) {
71
+ return false
72
+ }
73
+
74
+ const currentVersion = getColorPaletteVersion(config)
75
+ return (
76
+ currentVersion === 1 ||
77
+ config?.general?.palette?.version === '1.0' ||
78
+ !config?.general?.palette?.version
79
+ )
80
+ }
81
+
82
+ /**
83
+ * Returns the appropriate fallback color palette based on the palette version
84
+ * @param config - The visualization config object
85
+ * @returns The fallback palette name for the detected version
86
+ */
87
+ export const getFallbackColorPalette = (config: any): string => {
88
+ const paletteVersion = getColorPaletteVersion(config)
89
+ return paletteVersion === 1 ? FALLBACK_COLOR_PALETTE_V1 : FALLBACK_COLOR_PALETTE_V2
90
+ }
91
+
92
+ /**
93
+ * Finds a palette name in a migration map using exact match first, then case-insensitive fallback
94
+ * @param paletteName - The palette name to look up
95
+ * @param migrationMap - The migration map to search in
96
+ * @returns The migrated palette name or null if not found
97
+ */
98
+ export const findPaletteInMigrationMap = (paletteName: string, migrationMap: Record<string, string>): string | null => {
99
+ // Try exact match first
100
+ if (migrationMap[paletteName]) {
101
+ return migrationMap[paletteName]
102
+ }
103
+
104
+ // Try case-insensitive match
105
+ const lowerCaseName = paletteName.toLowerCase()
106
+ const matchingKey = Object.keys(migrationMap).find(key => key.toLowerCase() === lowerCaseName)
107
+
108
+ return matchingKey ? migrationMap[matchingKey] : null
109
+ }
110
+
111
+ /**
112
+ * Handles reverse palette suffix logic for chart palettes
113
+ * @param originalPaletteName - The original palette name that may have 'reverse' suffix
114
+ * @param migratedBase - The migrated base name
115
+ * @returns The properly formatted migrated palette name with reverse suffix if needed
116
+ */
117
+ export const handleReversePalette = (originalPaletteName: string, migratedBase: string): string => {
118
+ const isReverse = originalPaletteName.endsWith('reverse')
119
+ return isReverse ? migratedBase + 'reverse' : migratedBase
120
+ }
121
+
122
+ /**
123
+ * Generic migration function that works with any migration map
124
+ * @param oldPaletteName - The palette name to migrate
125
+ * @param migrationMap - The migration map to use
126
+ * @param handleReverse - Whether to handle reverse palette suffixes (for chart palettes)
127
+ * @returns The migrated palette name or original if no migration found
128
+ */
129
+ export const migratePaletteWithMap = (
130
+ oldPaletteName: string,
131
+ migrationMap: Record<string, string>,
132
+ handleReverse: boolean = false
133
+ ): string => {
134
+ // Handle null/undefined/empty cases - maintain original behavior
135
+ if (!oldPaletteName) {
136
+ return oldPaletteName
137
+ }
138
+
139
+ if (handleReverse) {
140
+ // Chart palette logic - handle reverse suffix
141
+ const isReverse = oldPaletteName.endsWith('reverse')
142
+ const basePaletteName = isReverse ? oldPaletteName.slice(0, -7) : oldPaletteName
143
+
144
+ const migratedBase = findPaletteInMigrationMap(basePaletteName, migrationMap)
145
+ if (migratedBase) {
146
+ return handleReversePalette(oldPaletteName, migratedBase)
147
+ }
148
+ } else {
149
+ // Map palette logic - direct lookup
150
+ const migrated = findPaletteInMigrationMap(oldPaletteName, migrationMap)
151
+ if (migrated) {
152
+ return migrated
153
+ }
154
+ }
155
+
156
+ return oldPaletteName
157
+ }
158
+
159
+ /**
160
+ * Checks if a config has palette backup data available for rollback
161
+ * @param config - The visualization config object
162
+ * @returns True if backup data exists
163
+ */
164
+ export const hasPaletteBackup = (config: any): boolean => {
165
+ return !!(config?.general?.palette?.backups?.length > 0)
166
+ }
167
+
168
+ /**
169
+ * Gets the original palette name from backup data
170
+ * @param config - The visualization config object
171
+ * @returns The original palette name or null if no backup exists
172
+ */
173
+ export const getOriginalPaletteName = (config: any): string | null => {
174
+ const backups = config?.general?.palette?.backups
175
+ if (!backups || backups.length === 0) return null
176
+
177
+ // Get the most recent backup (last in array)
178
+ const latestBackup = backups[backups.length - 1]
179
+ return latestBackup?.name || null
180
+ }
181
+
182
+ /**
183
+ * Gets the original two-color palette name from backup data
184
+ * @param config - The visualization config object
185
+ * @returns The original two-color palette name or null if no backup exists
186
+ */
187
+ export const getOriginalTwoColorPaletteName = (config: any): string | null => {
188
+ const backups = config?.general?.palette?.backups
189
+ if (!backups || backups.length === 0) return null
190
+
191
+ // Find the two-color palette backup
192
+ const twoColorBackup = backups.find((backup: any) => backup.type === 'twoColor')
193
+ return twoColorBackup?.name || null
194
+ }
195
+
196
+ /**
197
+ * Checks if a config has two-color palette backup data available for rollback
198
+ * @param config - The visualization config object
199
+ * @returns True if two-color backup data exists
200
+ */
201
+ export const hasTwoColorPaletteBackup = (config: any): boolean => {
202
+ const backups = config?.general?.palette?.backups
203
+ if (!backups || backups.length === 0) return false
204
+ return backups.some((backup: any) => backup.type === 'twoColor')
205
+ }
206
+
207
+ /**
208
+ * Rolls back palette configuration to original pre-migration state
209
+ * @param config - The visualization config object to modify
210
+ * @returns True if rollback was successful, false if no backup available
211
+ */
212
+ export const rollbackPaletteToOriginal = (config: any): boolean => {
213
+ const backups = config?.general?.palette?.backups
214
+ if (!backups || backups.length === 0) {
215
+ return false
216
+ }
217
+
218
+ // Get the most recent backup
219
+ const latestBackup = backups[backups.length - 1]
220
+ if (!latestBackup?.name) {
221
+ return false
222
+ }
223
+
224
+ // Restore the original configuration
225
+ if (config.type === 'map') {
226
+ config.general.palette.name = newMapPaletteNames[latestBackup.name] || latestBackup.name
227
+ config.general.palette.version = '1.0' // Reset to v1
228
+ } else if (config.type === 'chart') {
229
+ config.general.palette.name = chartPaletteMigrationMap[latestBackup.name] || latestBackup.name
230
+ config.general.palette.version = '1.0' // Reset to v1
231
+ }
232
+
233
+ return config
234
+ }
235
+
236
+ /**
237
+ * Rolls back two-color palette configuration to original pre-migration state
238
+ * @param config - The visualization config object to modify
239
+ * @returns True if rollback was successful, false if no backup available
240
+ */
241
+ export const rollbackTwoColorPaletteToOriginal = (config: any): boolean => {
242
+ const backups = config?.general?.palette?.backups
243
+ if (!backups || backups.length === 0) {
244
+ return false
245
+ }
246
+
247
+ // Find the two-color palette backup
248
+ const twoColorBackup = backups.find((backup: any) => backup.type === 'twoColor')
249
+ if (!twoColorBackup?.name) {
250
+ return false
251
+ }
252
+
253
+ // Restore the original two-color palette configuration
254
+ if (config.twoColor) {
255
+ config.twoColor.palette = twoColorBackup.name
256
+ config.twoColor.isPaletteReversed = twoColorBackup.isReversed || false
257
+ }
258
+
259
+ // Reset to v1
260
+ if (config.general?.palette) {
261
+ config.general.palette.version = twoColorBackup.version || '1.0'
262
+ // Remove the two-color backup since we've rolled back
263
+ config.general.palette.backups = backups.filter((backup: any) => backup.type !== 'twoColor')
264
+ }
265
+
266
+ return true
267
+ }
@@ -0,0 +1,65 @@
1
+ import Papa from 'papaparse'
2
+
3
+ /**
4
+ * Parses CSV text while preserving newlines and commas within quoted fields.
5
+ *
6
+ * @param responseText - The raw CSV text to parse
7
+ * @param options - Parsing options
8
+ * @param options.delimiter - The delimiter to use after processing (default: '|')
9
+ * @param options.dynamicTyping - Whether to automatically convert types (default: false)
10
+ * @returns Parsed CSV data as an array of objects
11
+ */
12
+ export function parseCsvWithQuotes(
13
+ responseText: string,
14
+ options: {
15
+ delimiter?: string
16
+ dynamicTyping?: boolean
17
+ } = {}
18
+ ): any[] {
19
+ const { delimiter = '|', dynamicTyping = false } = options
20
+
21
+ const NEWLINE_PLACEHOLDER = '__COVE_NEWLINE__'
22
+
23
+ // Preserve newlines in quoted fields by replacing with placeholder
24
+ const quotedFields: string[] = []
25
+ let placeholderIndex = 0
26
+ let sanitizedText = responseText.replace(/("(?:[^"\\]|\\.|[\s\S])*?")/g, (match) => {
27
+ const preserved = match.replace(/\n/g, NEWLINE_PLACEHOLDER)
28
+ quotedFields.push(preserved)
29
+ return `__QUOTED_FIELD_${placeholderIndex++}__`
30
+ })
31
+
32
+ // Replace commas outside quoted fields with pipe delimiter
33
+ sanitizedText = sanitizedText.replace(/(__QUOTED_FIELD_\d+__)|,/g, (...m) => m[1] || delimiter)
34
+
35
+ // Restore quoted fields without outer quotes
36
+ quotedFields.forEach((field, index) => {
37
+ const unquoted = field.slice(1, -1).replace(new RegExp(NEWLINE_PLACEHOLDER, 'g'), '\n')
38
+ sanitizedText = sanitizedText.replace(`__QUOTED_FIELD_${index}__`, unquoted)
39
+ })
40
+
41
+ // Parse with Papa.parse
42
+ const parsedCsv = Papa.parse(sanitizedText, {
43
+ header: true,
44
+ skipEmptyLines: true,
45
+ delimiter,
46
+ dynamicTyping
47
+ })
48
+
49
+ // Restore newlines in parsed data
50
+ const restoredData = parsedCsv.data.map((row: any) => {
51
+ const restoredRow: any = {}
52
+ Object.keys(row).forEach(key => {
53
+ const value = row[key]
54
+ if (typeof value === 'string') {
55
+ restoredRow[key] = value.replace(new RegExp(NEWLINE_PLACEHOLDER, 'g'), '\n')
56
+ } else {
57
+ restoredRow[key] = value
58
+ }
59
+ })
60
+ return restoredRow
61
+ })
62
+
63
+ return restoredData
64
+ }
65
+
@@ -49,3 +49,16 @@ export function removeQueryParam(key: string) {
49
49
  delete queryParams[key]
50
50
  updateQueryString(queryParams)
51
51
  }
52
+
53
+ /**
54
+ * Checks if developer mode is enabled via URL parameter
55
+ * @returns true if isCoveDeveloper URL parameter is present and truthy
56
+ */
57
+ export function isCoveDeveloperMode(): boolean {
58
+ const param = getQueryParam('isCoveDeveloper')
59
+ if (!param) return false
60
+
61
+ // Handle various truthy values
62
+ const lowerParam = param.toLowerCase()
63
+ return lowerParam === 'true' || lowerParam === '1' || lowerParam === 'yes'
64
+ }