@carto/ps-react-ui 4.7.1 → 4.9.0

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 (580) hide show
  1. package/dist/category-DwaeYjpX.js +656 -0
  2. package/dist/category-DwaeYjpX.js.map +1 -0
  3. package/dist/change-column-Cidl_M-4.js +1110 -0
  4. package/dist/change-column-Cidl_M-4.js.map +1 -0
  5. package/dist/data-zoom-layout-BH0LPwSy.js +28 -0
  6. package/dist/data-zoom-layout-BH0LPwSy.js.map +1 -0
  7. package/dist/echart-CU0KmClP.js +176 -0
  8. package/dist/echart-CU0KmClP.js.map +1 -0
  9. package/dist/exports-Cx-f6m6U.js +63 -0
  10. package/dist/exports-Cx-f6m6U.js.map +1 -0
  11. package/dist/formula-DuC0NQLH.js +79 -0
  12. package/dist/formula-DuC0NQLH.js.map +1 -0
  13. package/dist/markdown-BD1jcknS.js +8326 -0
  14. package/dist/markdown-BD1jcknS.js.map +1 -0
  15. package/dist/{styles-BYTyKQFP.js → option-builders-F-c9ELi1.js} +25 -45
  16. package/dist/option-builders-F-c9ELi1.js.map +1 -0
  17. package/dist/png-item-CS4z1iSH.js +45 -0
  18. package/dist/png-item-CS4z1iSH.js.map +1 -0
  19. package/dist/range-l4fNHLEg.js +213 -0
  20. package/dist/range-l4fNHLEg.js.map +1 -0
  21. package/dist/resolve-theme-color-BdojIw0K.js +47 -0
  22. package/dist/resolve-theme-color-BdojIw0K.js.map +1 -0
  23. package/dist/spread-CTuIXZSM.js +67 -0
  24. package/dist/spread-CTuIXZSM.js.map +1 -0
  25. package/dist/style-DVnT6HC1.js +131 -0
  26. package/dist/style-DVnT6HC1.js.map +1 -0
  27. package/dist/styles-cohnxh9F.js +23 -0
  28. package/dist/styles-cohnxh9F.js.map +1 -0
  29. package/dist/table-CQCAnDLb.js +388 -0
  30. package/dist/table-CQCAnDLb.js.map +1 -0
  31. package/dist/transforms-Cdx4fkU5.js +106 -0
  32. package/dist/transforms-Cdx4fkU5.js.map +1 -0
  33. package/dist/types/widgets/echart/utils.test.d.ts +1 -0
  34. package/dist/types/widgets/formula/config.test.d.ts +1 -0
  35. package/dist/types/widgets/stores/widget-store-branches.test.d.ts +1 -0
  36. package/dist/types/widgets/table/config.test.d.ts +1 -0
  37. package/dist/types/widgets-v2/actions/brush-toggle/brush-toggle.d.ts +56 -0
  38. package/dist/types/widgets-v2/actions/brush-toggle/index.d.ts +3 -0
  39. package/dist/types/widgets-v2/actions/brush-toggle/labels.d.ts +5 -0
  40. package/dist/types/widgets-v2/actions/brush-toggle/style.d.ts +12 -0
  41. package/dist/types/widgets-v2/actions/brush-toggle/transforms.d.ts +11 -0
  42. package/dist/types/widgets-v2/actions/brush-toggle/transforms.test.d.ts +1 -0
  43. package/dist/types/widgets-v2/actions/change-column/change-column-icon.d.ts +2 -0
  44. package/dist/types/widgets-v2/actions/change-column/change-column.d.ts +29 -0
  45. package/dist/types/widgets-v2/actions/change-column/index.d.ts +3 -0
  46. package/dist/types/widgets-v2/actions/change-column/labels.d.ts +5 -0
  47. package/dist/types/widgets-v2/actions/change-column/sortable-column-item.d.ts +14 -0
  48. package/dist/types/widgets-v2/actions/change-column/style.d.ts +33 -0
  49. package/dist/types/widgets-v2/actions/change-column/types.d.ts +10 -0
  50. package/dist/types/widgets-v2/actions/download/download.d.ts +18 -0
  51. package/dist/types/widgets-v2/actions/download/exports.d.ts +37 -0
  52. package/dist/types/widgets-v2/actions/download/icons.d.ts +12 -0
  53. package/dist/types/widgets-v2/actions/download/index.d.ts +6 -0
  54. package/dist/types/widgets-v2/actions/download/labels.d.ts +11 -0
  55. package/dist/types/widgets-v2/actions/download/png-item.d.ts +24 -0
  56. package/dist/types/widgets-v2/actions/download/style.d.ts +1 -0
  57. package/dist/types/widgets-v2/actions/download/types.d.ts +35 -0
  58. package/dist/types/widgets-v2/actions/fullscreen/fullscreen.d.ts +59 -0
  59. package/dist/types/widgets-v2/actions/fullscreen/index.d.ts +3 -0
  60. package/dist/types/widgets-v2/actions/fullscreen/labels.d.ts +5 -0
  61. package/dist/types/widgets-v2/actions/fullscreen/style.d.ts +48 -0
  62. package/dist/types/widgets-v2/actions/fullscreen/types.d.ts +14 -0
  63. package/dist/types/widgets-v2/actions/index.d.ts +9 -0
  64. package/dist/types/widgets-v2/actions/lock-selection/index.d.ts +3 -0
  65. package/dist/types/widgets-v2/actions/lock-selection/labels.d.ts +6 -0
  66. package/dist/types/widgets-v2/actions/lock-selection/lock-selection.d.ts +36 -0
  67. package/dist/types/widgets-v2/actions/lock-selection/style.d.ts +12 -0
  68. package/dist/types/widgets-v2/actions/lock-selection/transforms.d.ts +6 -0
  69. package/dist/types/widgets-v2/actions/relative-data/index.d.ts +3 -0
  70. package/dist/types/widgets-v2/actions/relative-data/labels.d.ts +5 -0
  71. package/dist/types/widgets-v2/actions/relative-data/relative-data.d.ts +39 -0
  72. package/dist/types/widgets-v2/actions/relative-data/style.d.ts +12 -0
  73. package/dist/types/widgets-v2/actions/relative-data/transforms.d.ts +30 -0
  74. package/dist/types/widgets-v2/actions/relative-data/transforms.test.d.ts +1 -0
  75. package/dist/types/widgets-v2/actions/searcher/filter.d.ts +6 -0
  76. package/dist/types/widgets-v2/actions/searcher/index.d.ts +4 -0
  77. package/dist/types/widgets-v2/actions/searcher/labels.d.ts +7 -0
  78. package/dist/types/widgets-v2/actions/searcher/searcher-toggle.d.ts +23 -0
  79. package/dist/types/widgets-v2/actions/searcher/searcher.d.ts +11 -0
  80. package/dist/types/widgets-v2/actions/searcher/style.d.ts +16 -0
  81. package/dist/types/widgets-v2/actions/stack-toggle/index.d.ts +3 -0
  82. package/dist/types/widgets-v2/actions/stack-toggle/labels.d.ts +5 -0
  83. package/dist/types/widgets-v2/actions/stack-toggle/stack-toggle.d.ts +10 -0
  84. package/dist/types/widgets-v2/actions/stack-toggle/style.d.ts +12 -0
  85. package/dist/types/widgets-v2/actions/stack-toggle/transforms.d.ts +13 -0
  86. package/dist/types/widgets-v2/actions/stack-toggle/transforms.test.d.ts +1 -0
  87. package/dist/types/widgets-v2/actions/zoom-toggle/index.d.ts +3 -0
  88. package/dist/types/widgets-v2/actions/zoom-toggle/labels.d.ts +5 -0
  89. package/dist/types/widgets-v2/actions/zoom-toggle/style.d.ts +12 -0
  90. package/dist/types/widgets-v2/actions/zoom-toggle/transforms.d.ts +51 -0
  91. package/dist/types/widgets-v2/actions/zoom-toggle/transforms.test.d.ts +1 -0
  92. package/dist/types/widgets-v2/actions/zoom-toggle/zoom-toggle.d.ts +35 -0
  93. package/dist/types/widgets-v2/bar/download.d.ts +24 -0
  94. package/dist/types/widgets-v2/bar/index.d.ts +4 -0
  95. package/dist/types/widgets-v2/bar/options.d.ts +43 -0
  96. package/dist/types/widgets-v2/bar/options.test.d.ts +1 -0
  97. package/dist/types/widgets-v2/bar/skeleton.d.ts +6 -0
  98. package/dist/types/widgets-v2/bar/types.d.ts +46 -0
  99. package/dist/types/widgets-v2/category/category-ui.d.ts +81 -0
  100. package/dist/types/widgets-v2/category/category.d.ts +48 -0
  101. package/dist/types/widgets-v2/category/components/category-bar-stacked.d.ts +28 -0
  102. package/dist/types/widgets-v2/category/components/category-bar.d.ts +23 -0
  103. package/dist/types/widgets-v2/category/components/category-legend.d.ts +18 -0
  104. package/dist/types/widgets-v2/category/components/category-row-multi.d.ts +31 -0
  105. package/dist/types/widgets-v2/category/components/category-row-other.d.ts +13 -0
  106. package/dist/types/widgets-v2/category/components/category-row-single.d.ts +28 -0
  107. package/dist/types/widgets-v2/category/components/category-row-stacked.d.ts +38 -0
  108. package/dist/types/widgets-v2/category/download.d.ts +16 -0
  109. package/dist/types/widgets-v2/category/download.test.d.ts +1 -0
  110. package/dist/types/widgets-v2/category/index.d.ts +10 -0
  111. package/dist/types/widgets-v2/category/skeleton.d.ts +11 -0
  112. package/dist/types/widgets-v2/category/style.d.ts +166 -0
  113. package/dist/types/widgets-v2/category/types.d.ts +53 -0
  114. package/dist/types/widgets-v2/echart/echart-ui.d.ts +44 -0
  115. package/dist/types/widgets-v2/echart/echart.d.ts +75 -0
  116. package/dist/types/widgets-v2/echart/index.d.ts +4 -0
  117. package/dist/types/widgets-v2/echart/shared-resize-observer.d.ts +5 -0
  118. package/dist/types/widgets-v2/echart/shared-resize-observer.test.d.ts +1 -0
  119. package/dist/types/widgets-v2/echart/style.d.ts +6 -0
  120. package/dist/types/widgets-v2/echart/use-chart-selection.d.ts +51 -0
  121. package/dist/types/widgets-v2/formula/delta.d.ts +22 -0
  122. package/dist/types/widgets-v2/formula/download.d.ts +20 -0
  123. package/dist/types/widgets-v2/formula/formula-ui.d.ts +20 -0
  124. package/dist/types/widgets-v2/formula/formula.d.ts +8 -0
  125. package/dist/types/widgets-v2/formula/index.d.ts +11 -0
  126. package/dist/types/widgets-v2/formula/note.d.ts +11 -0
  127. package/dist/types/widgets-v2/formula/prefix.d.ts +12 -0
  128. package/dist/types/widgets-v2/formula/series.d.ts +16 -0
  129. package/dist/types/widgets-v2/formula/skeleton.d.ts +4 -0
  130. package/dist/types/widgets-v2/formula/style.d.ts +29 -0
  131. package/dist/types/widgets-v2/formula/suffix.d.ts +12 -0
  132. package/dist/types/widgets-v2/formula/types.d.ts +43 -0
  133. package/dist/types/widgets-v2/formula/value.d.ts +14 -0
  134. package/dist/types/widgets-v2/histogram/download.d.ts +17 -0
  135. package/dist/types/widgets-v2/histogram/download.test.d.ts +1 -0
  136. package/dist/types/widgets-v2/histogram/index.d.ts +5 -0
  137. package/dist/types/widgets-v2/histogram/options.d.ts +42 -0
  138. package/dist/types/widgets-v2/histogram/options.test.d.ts +1 -0
  139. package/dist/types/widgets-v2/histogram/skeleton.d.ts +9 -0
  140. package/dist/types/widgets-v2/histogram/transforms.d.ts +17 -0
  141. package/dist/types/widgets-v2/histogram/transforms.test.d.ts +1 -0
  142. package/dist/types/widgets-v2/histogram/types.d.ts +51 -0
  143. package/dist/types/widgets-v2/index.d.ts +108 -0
  144. package/dist/types/widgets-v2/markdown/download.d.ts +16 -0
  145. package/dist/types/widgets-v2/markdown/download.test.d.ts +1 -0
  146. package/dist/types/widgets-v2/markdown/index.d.ts +6 -0
  147. package/dist/types/widgets-v2/markdown/markdown-content.d.ts +34 -0
  148. package/dist/types/widgets-v2/markdown/markdown-ui.d.ts +12 -0
  149. package/dist/types/widgets-v2/markdown/markdown.d.ts +6 -0
  150. package/dist/types/widgets-v2/markdown/skeleton.d.ts +4 -0
  151. package/dist/types/widgets-v2/markdown/style.d.ts +61 -0
  152. package/dist/types/widgets-v2/markdown/types.d.ts +4 -0
  153. package/dist/types/widgets-v2/note/labels.d.ts +5 -0
  154. package/dist/types/widgets-v2/note/style.d.ts +26 -0
  155. package/dist/types/widgets-v2/note/widget-note.d.ts +46 -0
  156. package/dist/types/widgets-v2/pie/download.d.ts +17 -0
  157. package/dist/types/widgets-v2/pie/download.test.d.ts +1 -0
  158. package/dist/types/widgets-v2/pie/index.d.ts +4 -0
  159. package/dist/types/widgets-v2/pie/options.d.ts +35 -0
  160. package/dist/types/widgets-v2/pie/options.test.d.ts +1 -0
  161. package/dist/types/widgets-v2/pie/skeleton.d.ts +4 -0
  162. package/dist/types/widgets-v2/pie/types.d.ts +57 -0
  163. package/dist/types/widgets-v2/provider/widget-provider.d.ts +32 -0
  164. package/dist/types/widgets-v2/range/index.d.ts +4 -0
  165. package/dist/types/widgets-v2/range/range-ui.d.ts +27 -0
  166. package/dist/types/widgets-v2/range/range.d.ts +24 -0
  167. package/dist/types/widgets-v2/range/skeleton.d.ts +9 -0
  168. package/dist/types/widgets-v2/range/style.d.ts +40 -0
  169. package/dist/types/widgets-v2/range/types.d.ts +37 -0
  170. package/dist/types/widgets-v2/scatterplot/download.d.ts +16 -0
  171. package/dist/types/widgets-v2/scatterplot/download.test.d.ts +1 -0
  172. package/dist/types/widgets-v2/scatterplot/index.d.ts +5 -0
  173. package/dist/types/widgets-v2/scatterplot/options.d.ts +42 -0
  174. package/dist/types/widgets-v2/scatterplot/options.test.d.ts +1 -0
  175. package/dist/types/widgets-v2/scatterplot/skeleton.d.ts +12 -0
  176. package/dist/types/widgets-v2/scatterplot/transforms.d.ts +17 -0
  177. package/dist/types/widgets-v2/scatterplot/transforms.test.d.ts +1 -0
  178. package/dist/types/widgets-v2/scatterplot/types.d.ts +54 -0
  179. package/dist/types/widgets-v2/selection-summary/labels.d.ts +6 -0
  180. package/dist/types/widgets-v2/selection-summary/selection-summary.d.ts +22 -0
  181. package/dist/types/widgets-v2/selection-summary/style.d.ts +23 -0
  182. package/dist/types/widgets-v2/spread/download.d.ts +15 -0
  183. package/dist/types/widgets-v2/spread/download.test.d.ts +1 -0
  184. package/dist/types/widgets-v2/spread/index.d.ts +6 -0
  185. package/dist/types/widgets-v2/spread/separator.d.ts +7 -0
  186. package/dist/types/widgets-v2/spread/skeleton.d.ts +9 -0
  187. package/dist/types/widgets-v2/spread/spread-ui.d.ts +18 -0
  188. package/dist/types/widgets-v2/spread/spread.d.ts +5 -0
  189. package/dist/types/widgets-v2/spread/types.d.ts +25 -0
  190. package/dist/types/widgets-v2/state/labels.d.ts +7 -0
  191. package/dist/types/widgets-v2/state/labels.test.d.ts +1 -0
  192. package/dist/types/widgets-v2/state/style.d.ts +19 -0
  193. package/dist/types/widgets-v2/state/widget-state.d.ts +19 -0
  194. package/dist/types/widgets-v2/stores/index.d.ts +8 -0
  195. package/dist/types/widgets-v2/stores/pipeline-middleware.d.ts +5 -0
  196. package/dist/types/widgets-v2/stores/pipeline-middleware.test.d.ts +1 -0
  197. package/dist/types/widgets-v2/stores/transforms.d.ts +4 -0
  198. package/dist/types/widgets-v2/stores/transforms.test.d.ts +1 -0
  199. package/dist/types/widgets-v2/stores/types.d.ts +55 -0
  200. package/dist/types/widgets-v2/stores/use-echart-instance.d.ts +15 -0
  201. package/dist/types/widgets-v2/stores/use-transform-enabled.d.ts +17 -0
  202. package/dist/types/widgets-v2/stores/use-transform.d.ts +12 -0
  203. package/dist/types/widgets-v2/stores/widget-context.d.ts +2 -0
  204. package/dist/types/widgets-v2/stores/widget-store-registry.d.ts +74 -0
  205. package/dist/types/widgets-v2/stores/widget-store-registry.test.d.ts +1 -0
  206. package/dist/types/widgets-v2/subheader/style.d.ts +10 -0
  207. package/dist/types/widgets-v2/subheader/subheader.d.ts +11 -0
  208. package/dist/types/widgets-v2/table/download.d.ts +18 -0
  209. package/dist/types/widgets-v2/table/download.test.d.ts +1 -0
  210. package/dist/types/widgets-v2/table/helpers.d.ts +32 -0
  211. package/dist/types/widgets-v2/table/helpers.test.d.ts +1 -0
  212. package/dist/types/widgets-v2/table/index.d.ts +7 -0
  213. package/dist/types/widgets-v2/table/labels.d.ts +22 -0
  214. package/dist/types/widgets-v2/table/skeleton.d.ts +22 -0
  215. package/dist/types/widgets-v2/table/style.d.ts +40 -0
  216. package/dist/types/widgets-v2/table/table-ui.d.ts +44 -0
  217. package/dist/types/widgets-v2/table/table.d.ts +50 -0
  218. package/dist/types/widgets-v2/table/types.d.ts +48 -0
  219. package/dist/types/widgets-v2/test-utils.d.ts +52 -0
  220. package/dist/types/widgets-v2/timeseries/download.d.ts +17 -0
  221. package/dist/types/widgets-v2/timeseries/download.test.d.ts +1 -0
  222. package/dist/types/widgets-v2/timeseries/index.d.ts +4 -0
  223. package/dist/types/widgets-v2/timeseries/options.d.ts +39 -0
  224. package/dist/types/widgets-v2/timeseries/options.test.d.ts +1 -0
  225. package/dist/types/widgets-v2/timeseries/skeleton.d.ts +8 -0
  226. package/dist/types/widgets-v2/timeseries/types.d.ts +60 -0
  227. package/dist/types/widgets-v2/toolbox/labels.d.ts +5 -0
  228. package/dist/types/widgets-v2/toolbox/style.d.ts +30 -0
  229. package/dist/types/widgets-v2/toolbox/toolbox.d.ts +49 -0
  230. package/dist/types/widgets-v2/types.d.ts +25 -0
  231. package/dist/types/widgets-v2/utils/data-zoom-layout.d.ts +11 -0
  232. package/dist/types/widgets-v2/utils/index.d.ts +3 -0
  233. package/dist/types/widgets-v2/utils/merge-options.d.ts +12 -0
  234. package/dist/types/widgets-v2/utils/merge-options.test.d.ts +1 -0
  235. package/dist/types/widgets-v2/utils/resolve-theme-color.d.ts +18 -0
  236. package/dist/types/widgets-v2/utils/resolve-theme-color.test.d.ts +1 -0
  237. package/dist/types/widgets-v2/wrapper/index.d.ts +4 -0
  238. package/dist/types/widgets-v2/wrapper/labels.d.ts +6 -0
  239. package/dist/types/widgets-v2/wrapper/style.d.ts +111 -0
  240. package/dist/types/widgets-v2/wrapper/widget-actions.d.ts +22 -0
  241. package/dist/types/widgets-v2/wrapper/widget-content.d.ts +12 -0
  242. package/dist/types/widgets-v2/wrapper/widget-wrapper.d.ts +51 -0
  243. package/dist/use-transform-DXPN3nY7.js +110 -0
  244. package/dist/use-transform-DXPN3nY7.js.map +1 -0
  245. package/dist/widget-context-DTGO0Yta.js +13 -0
  246. package/dist/widget-context-DTGO0Yta.js.map +1 -0
  247. package/dist/widget-store-registry-_W4Z4xp-.js +178 -0
  248. package/dist/widget-store-registry-_W4Z4xp-.js.map +1 -0
  249. package/dist/widgets/bar.js +14 -13
  250. package/dist/widgets/bar.js.map +1 -1
  251. package/dist/widgets/histogram.js +8 -7
  252. package/dist/widgets/histogram.js.map +1 -1
  253. package/dist/widgets/pie.js +19 -18
  254. package/dist/widgets/pie.js.map +1 -1
  255. package/dist/widgets/scatterplot.js +8 -7
  256. package/dist/widgets/scatterplot.js.map +1 -1
  257. package/dist/widgets/timeseries.js +11 -10
  258. package/dist/widgets/timeseries.js.map +1 -1
  259. package/dist/widgets/utils.js +8 -7
  260. package/dist/widgets/utils.js.map +1 -1
  261. package/dist/widgets-v2/actions.js +43 -0
  262. package/dist/widgets-v2/actions.js.map +1 -0
  263. package/dist/widgets-v2/bar.js +330 -0
  264. package/dist/widgets-v2/bar.js.map +1 -0
  265. package/dist/widgets-v2/category.js +104 -0
  266. package/dist/widgets-v2/category.js.map +1 -0
  267. package/dist/widgets-v2/echart.js +57 -0
  268. package/dist/widgets-v2/echart.js.map +1 -0
  269. package/dist/widgets-v2/formula.js +74 -0
  270. package/dist/widgets-v2/formula.js.map +1 -0
  271. package/dist/widgets-v2/histogram.js +353 -0
  272. package/dist/widgets-v2/histogram.js.map +1 -0
  273. package/dist/widgets-v2/markdown.js +68 -0
  274. package/dist/widgets-v2/markdown.js.map +1 -0
  275. package/dist/widgets-v2/pie.js +387 -0
  276. package/dist/widgets-v2/pie.js.map +1 -0
  277. package/dist/widgets-v2/range.js +52 -0
  278. package/dist/widgets-v2/range.js.map +1 -0
  279. package/dist/widgets-v2/scatterplot.js +411 -0
  280. package/dist/widgets-v2/scatterplot.js.map +1 -0
  281. package/dist/widgets-v2/spread.js +72 -0
  282. package/dist/widgets-v2/spread.js.map +1 -0
  283. package/dist/widgets-v2/stores.js +42 -0
  284. package/dist/widgets-v2/stores.js.map +1 -0
  285. package/dist/widgets-v2/table.js +78 -0
  286. package/dist/widgets-v2/table.js.map +1 -0
  287. package/dist/widgets-v2/timeseries.js +358 -0
  288. package/dist/widgets-v2/timeseries.js.map +1 -0
  289. package/dist/widgets-v2/utils.js +8 -0
  290. package/dist/widgets-v2/utils.js.map +1 -0
  291. package/dist/widgets-v2.js +953 -0
  292. package/dist/widgets-v2.js.map +1 -0
  293. package/package.json +71 -3
  294. package/src/components/lasso-tool/chip.test.tsx +176 -0
  295. package/src/components/lasso-tool/lasso-tool-inline.test.tsx +171 -0
  296. package/src/components/lasso-tool/lasso-tool.test.tsx +198 -0
  297. package/src/components/list-data/list-data.test.tsx +73 -0
  298. package/src/components/no-data-alert/no-data-alert.test.tsx +38 -0
  299. package/src/components/responsive-drawer/responsive-drawer.test.tsx +68 -0
  300. package/src/widgets/actions/brush-toggle/brush-overlay.test.tsx +465 -0
  301. package/src/widgets/actions/brush-toggle/brush-toggle.test.tsx +208 -0
  302. package/src/widgets/actions/change-column/change-column-dnd.test.tsx +193 -0
  303. package/src/widgets/actions/change-column/sortable-column-item.test.tsx +124 -0
  304. package/src/widgets/actions/zoom-toggle/zoom-toggle.test.tsx +322 -0
  305. package/src/widgets/category/components/category-rows.test.tsx +213 -0
  306. package/src/widgets/echart/utils.test.ts +277 -0
  307. package/src/widgets/formula/config.test.ts +37 -0
  308. package/src/widgets/range/components/range-item.test.tsx +243 -0
  309. package/src/widgets/stores/widget-store-branches.test.ts +275 -0
  310. package/src/widgets/table/config.test.ts +65 -0
  311. package/src/widgets/utils/chart-config/option-builders.test.ts +188 -0
  312. package/src/widgets-v2/PERFORMANCE.md +189 -0
  313. package/src/widgets-v2/actions/brush-toggle/brush-toggle.test.tsx +180 -0
  314. package/src/widgets-v2/actions/brush-toggle/brush-toggle.tsx +154 -0
  315. package/src/widgets-v2/actions/brush-toggle/index.ts +3 -0
  316. package/src/widgets-v2/actions/brush-toggle/labels.ts +9 -0
  317. package/src/widgets-v2/actions/brush-toggle/style.ts +11 -0
  318. package/src/widgets-v2/actions/brush-toggle/transforms.test.ts +47 -0
  319. package/src/widgets-v2/actions/brush-toggle/transforms.ts +31 -0
  320. package/src/widgets-v2/actions/change-column/change-column-icon.tsx +14 -0
  321. package/src/widgets-v2/actions/change-column/change-column.test.tsx +59 -0
  322. package/src/widgets-v2/actions/change-column/change-column.tsx +180 -0
  323. package/src/widgets-v2/actions/change-column/index.ts +7 -0
  324. package/src/widgets-v2/actions/change-column/labels.ts +9 -0
  325. package/src/widgets-v2/actions/change-column/sortable-column-item.tsx +56 -0
  326. package/src/widgets-v2/actions/change-column/style.ts +32 -0
  327. package/src/widgets-v2/actions/change-column/types.ts +11 -0
  328. package/src/widgets-v2/actions/download/download.test.tsx +327 -0
  329. package/src/widgets-v2/actions/download/download.tsx +144 -0
  330. package/src/widgets-v2/actions/download/exports.test.tsx +198 -0
  331. package/src/widgets-v2/actions/download/exports.ts +115 -0
  332. package/src/widgets-v2/actions/download/icons.tsx +26 -0
  333. package/src/widgets-v2/actions/download/index.ts +13 -0
  334. package/src/widgets-v2/actions/download/labels.ts +16 -0
  335. package/src/widgets-v2/actions/download/png-item.test.tsx +72 -0
  336. package/src/widgets-v2/actions/download/png-item.tsx +52 -0
  337. package/src/widgets-v2/actions/download/style.ts +3 -0
  338. package/src/widgets-v2/actions/download/types.ts +32 -0
  339. package/src/widgets-v2/actions/fullscreen/fullscreen.test.tsx +150 -0
  340. package/src/widgets-v2/actions/fullscreen/fullscreen.tsx +230 -0
  341. package/src/widgets-v2/actions/fullscreen/index.ts +7 -0
  342. package/src/widgets-v2/actions/fullscreen/labels.ts +9 -0
  343. package/src/widgets-v2/actions/fullscreen/style.ts +59 -0
  344. package/src/widgets-v2/actions/fullscreen/types.ts +15 -0
  345. package/src/widgets-v2/actions/index.ts +82 -0
  346. package/src/widgets-v2/actions/lock-selection/index.ts +10 -0
  347. package/src/widgets-v2/actions/lock-selection/labels.ts +11 -0
  348. package/src/widgets-v2/actions/lock-selection/lock-selection.test.tsx +187 -0
  349. package/src/widgets-v2/actions/lock-selection/lock-selection.tsx +130 -0
  350. package/src/widgets-v2/actions/lock-selection/style.ts +11 -0
  351. package/src/widgets-v2/actions/lock-selection/transforms.ts +27 -0
  352. package/src/widgets-v2/actions/relative-data/index.ts +3 -0
  353. package/src/widgets-v2/actions/relative-data/labels.ts +9 -0
  354. package/src/widgets-v2/actions/relative-data/relative-data.test.tsx +71 -0
  355. package/src/widgets-v2/actions/relative-data/relative-data.tsx +107 -0
  356. package/src/widgets-v2/actions/relative-data/style.ts +11 -0
  357. package/src/widgets-v2/actions/relative-data/transforms.test.ts +151 -0
  358. package/src/widgets-v2/actions/relative-data/transforms.ts +70 -0
  359. package/src/widgets-v2/actions/searcher/filter.ts +28 -0
  360. package/src/widgets-v2/actions/searcher/index.ts +8 -0
  361. package/src/widgets-v2/actions/searcher/labels.ts +13 -0
  362. package/src/widgets-v2/actions/searcher/searcher-toggle.tsx +91 -0
  363. package/src/widgets-v2/actions/searcher/searcher.test.tsx +92 -0
  364. package/src/widgets-v2/actions/searcher/searcher.tsx +112 -0
  365. package/src/widgets-v2/actions/searcher/style.ts +15 -0
  366. package/src/widgets-v2/actions/stack-toggle/index.ts +3 -0
  367. package/src/widgets-v2/actions/stack-toggle/labels.ts +9 -0
  368. package/src/widgets-v2/actions/stack-toggle/stack-toggle.test.tsx +61 -0
  369. package/src/widgets-v2/actions/stack-toggle/stack-toggle.tsx +54 -0
  370. package/src/widgets-v2/actions/stack-toggle/style.ts +11 -0
  371. package/src/widgets-v2/actions/stack-toggle/transforms.test.ts +43 -0
  372. package/src/widgets-v2/actions/stack-toggle/transforms.ts +25 -0
  373. package/src/widgets-v2/actions/zoom-toggle/index.ts +9 -0
  374. package/src/widgets-v2/actions/zoom-toggle/labels.ts +9 -0
  375. package/src/widgets-v2/actions/zoom-toggle/style.ts +11 -0
  376. package/src/widgets-v2/actions/zoom-toggle/transforms.test.ts +148 -0
  377. package/src/widgets-v2/actions/zoom-toggle/transforms.ts +171 -0
  378. package/src/widgets-v2/actions/zoom-toggle/zoom-toggle.test.tsx +107 -0
  379. package/src/widgets-v2/actions/zoom-toggle/zoom-toggle.tsx +106 -0
  380. package/src/widgets-v2/bar/download.test.tsx +91 -0
  381. package/src/widgets-v2/bar/download.tsx +66 -0
  382. package/src/widgets-v2/bar/index.ts +10 -0
  383. package/src/widgets-v2/bar/options.test.ts +334 -0
  384. package/src/widgets-v2/bar/options.ts +332 -0
  385. package/src/widgets-v2/bar/skeleton.test.tsx +19 -0
  386. package/src/widgets-v2/bar/skeleton.tsx +69 -0
  387. package/src/widgets-v2/bar/types.ts +51 -0
  388. package/src/widgets-v2/category/category-ui.test.tsx +746 -0
  389. package/src/widgets-v2/category/category-ui.tsx +389 -0
  390. package/src/widgets-v2/category/category.relative-data.test.tsx +107 -0
  391. package/src/widgets-v2/category/category.stack-toggle.test.tsx +85 -0
  392. package/src/widgets-v2/category/category.test.tsx +305 -0
  393. package/src/widgets-v2/category/category.tsx +121 -0
  394. package/src/widgets-v2/category/components/category-bar-stacked.test.tsx +121 -0
  395. package/src/widgets-v2/category/components/category-bar-stacked.tsx +73 -0
  396. package/src/widgets-v2/category/components/category-bar.test.tsx +64 -0
  397. package/src/widgets-v2/category/components/category-bar.tsx +49 -0
  398. package/src/widgets-v2/category/components/category-legend.test.tsx +51 -0
  399. package/src/widgets-v2/category/components/category-legend.tsx +39 -0
  400. package/src/widgets-v2/category/components/category-row-multi.tsx +86 -0
  401. package/src/widgets-v2/category/components/category-row-other.test.tsx +28 -0
  402. package/src/widgets-v2/category/components/category-row-other.tsx +33 -0
  403. package/src/widgets-v2/category/components/category-row-single.tsx +76 -0
  404. package/src/widgets-v2/category/components/category-row-stacked.test.tsx +244 -0
  405. package/src/widgets-v2/category/components/category-row-stacked.tsx +99 -0
  406. package/src/widgets-v2/category/download.test.ts +71 -0
  407. package/src/widgets-v2/category/download.ts +54 -0
  408. package/src/widgets-v2/category/index.ts +32 -0
  409. package/src/widgets-v2/category/skeleton.test.tsx +26 -0
  410. package/src/widgets-v2/category/skeleton.tsx +74 -0
  411. package/src/widgets-v2/category/style.ts +290 -0
  412. package/src/widgets-v2/category/types.ts +59 -0
  413. package/src/widgets-v2/echart/echart-ui.test.tsx +232 -0
  414. package/src/widgets-v2/echart/echart-ui.tsx +184 -0
  415. package/src/widgets-v2/echart/echart.test.tsx +229 -0
  416. package/src/widgets-v2/echart/echart.tsx +199 -0
  417. package/src/widgets-v2/echart/index.ts +22 -0
  418. package/src/widgets-v2/echart/shared-resize-observer.test.ts +91 -0
  419. package/src/widgets-v2/echart/shared-resize-observer.ts +56 -0
  420. package/src/widgets-v2/echart/style.ts +8 -0
  421. package/src/widgets-v2/echart/use-chart-selection.test.tsx +118 -0
  422. package/src/widgets-v2/echart/use-chart-selection.ts +115 -0
  423. package/src/widgets-v2/formula/delta.tsx +61 -0
  424. package/src/widgets-v2/formula/download.test.tsx +65 -0
  425. package/src/widgets-v2/formula/download.tsx +69 -0
  426. package/src/widgets-v2/formula/formula-ui.test.tsx +91 -0
  427. package/src/widgets-v2/formula/formula-ui.tsx +66 -0
  428. package/src/widgets-v2/formula/formula.test.tsx +50 -0
  429. package/src/widgets-v2/formula/formula.tsx +34 -0
  430. package/src/widgets-v2/formula/index.ts +17 -0
  431. package/src/widgets-v2/formula/note.tsx +25 -0
  432. package/src/widgets-v2/formula/prefix.tsx +25 -0
  433. package/src/widgets-v2/formula/series.tsx +67 -0
  434. package/src/widgets-v2/formula/skeleton.test.tsx +21 -0
  435. package/src/widgets-v2/formula/skeleton.tsx +27 -0
  436. package/src/widgets-v2/formula/style.ts +31 -0
  437. package/src/widgets-v2/formula/subcomponents.test.tsx +107 -0
  438. package/src/widgets-v2/formula/suffix.tsx +25 -0
  439. package/src/widgets-v2/formula/types.ts +48 -0
  440. package/src/widgets-v2/formula/value.tsx +31 -0
  441. package/src/widgets-v2/histogram/download.test.ts +94 -0
  442. package/src/widgets-v2/histogram/download.ts +60 -0
  443. package/src/widgets-v2/histogram/index.ts +10 -0
  444. package/src/widgets-v2/histogram/options.test.ts +318 -0
  445. package/src/widgets-v2/histogram/options.ts +338 -0
  446. package/src/widgets-v2/histogram/skeleton.test.tsx +16 -0
  447. package/src/widgets-v2/histogram/skeleton.tsx +70 -0
  448. package/src/widgets-v2/histogram/transforms.test.ts +46 -0
  449. package/src/widgets-v2/histogram/transforms.ts +30 -0
  450. package/src/widgets-v2/histogram/types.ts +55 -0
  451. package/src/widgets-v2/index.ts +204 -0
  452. package/src/widgets-v2/markdown/download.test.ts +66 -0
  453. package/src/widgets-v2/markdown/download.ts +53 -0
  454. package/src/widgets-v2/markdown/index.ts +6 -0
  455. package/src/widgets-v2/markdown/markdown-content.test.tsx +155 -0
  456. package/src/widgets-v2/markdown/markdown-content.tsx +72 -0
  457. package/src/widgets-v2/markdown/markdown-ui.test.tsx +75 -0
  458. package/src/widgets-v2/markdown/markdown-ui.tsx +55 -0
  459. package/src/widgets-v2/markdown/markdown.test.tsx +39 -0
  460. package/src/widgets-v2/markdown/markdown.tsx +17 -0
  461. package/src/widgets-v2/markdown/skeleton.test.tsx +15 -0
  462. package/src/widgets-v2/markdown/skeleton.tsx +32 -0
  463. package/src/widgets-v2/markdown/style.ts +53 -0
  464. package/src/widgets-v2/markdown/types.ts +4 -0
  465. package/src/widgets-v2/note/labels.ts +9 -0
  466. package/src/widgets-v2/note/style.ts +26 -0
  467. package/src/widgets-v2/note/widget-note.test.tsx +158 -0
  468. package/src/widgets-v2/note/widget-note.tsx +172 -0
  469. package/src/widgets-v2/pie/download.test.ts +78 -0
  470. package/src/widgets-v2/pie/download.ts +55 -0
  471. package/src/widgets-v2/pie/index.ts +10 -0
  472. package/src/widgets-v2/pie/options.test.ts +601 -0
  473. package/src/widgets-v2/pie/options.ts +513 -0
  474. package/src/widgets-v2/pie/skeleton.test.tsx +17 -0
  475. package/src/widgets-v2/pie/skeleton.tsx +32 -0
  476. package/src/widgets-v2/pie/types.ts +62 -0
  477. package/src/widgets-v2/provider/widget-provider.test.tsx +119 -0
  478. package/src/widgets-v2/provider/widget-provider.tsx +111 -0
  479. package/src/widgets-v2/range/index.ts +4 -0
  480. package/src/widgets-v2/range/range-ui.test.tsx +136 -0
  481. package/src/widgets-v2/range/range-ui.tsx +278 -0
  482. package/src/widgets-v2/range/range.test.tsx +68 -0
  483. package/src/widgets-v2/range/range.tsx +52 -0
  484. package/src/widgets-v2/range/skeleton.test.tsx +17 -0
  485. package/src/widgets-v2/range/skeleton.tsx +47 -0
  486. package/src/widgets-v2/range/style.ts +41 -0
  487. package/src/widgets-v2/range/types.ts +37 -0
  488. package/src/widgets-v2/scatterplot/download.test.ts +71 -0
  489. package/src/widgets-v2/scatterplot/download.ts +54 -0
  490. package/src/widgets-v2/scatterplot/index.ts +11 -0
  491. package/src/widgets-v2/scatterplot/options.test.ts +411 -0
  492. package/src/widgets-v2/scatterplot/options.ts +425 -0
  493. package/src/widgets-v2/scatterplot/skeleton.test.tsx +17 -0
  494. package/src/widgets-v2/scatterplot/skeleton.tsx +84 -0
  495. package/src/widgets-v2/scatterplot/transforms.test.ts +97 -0
  496. package/src/widgets-v2/scatterplot/transforms.ts +38 -0
  497. package/src/widgets-v2/scatterplot/types.ts +59 -0
  498. package/src/widgets-v2/selection-summary/labels.ts +11 -0
  499. package/src/widgets-v2/selection-summary/selection-summary.test.tsx +53 -0
  500. package/src/widgets-v2/selection-summary/selection-summary.tsx +62 -0
  501. package/src/widgets-v2/selection-summary/style.ts +23 -0
  502. package/src/widgets-v2/spread/download.test.ts +64 -0
  503. package/src/widgets-v2/spread/download.ts +59 -0
  504. package/src/widgets-v2/spread/index.ts +6 -0
  505. package/src/widgets-v2/spread/separator.tsx +11 -0
  506. package/src/widgets-v2/spread/skeleton.test.tsx +17 -0
  507. package/src/widgets-v2/spread/skeleton.tsx +38 -0
  508. package/src/widgets-v2/spread/spread-ui.test.tsx +108 -0
  509. package/src/widgets-v2/spread/spread-ui.tsx +52 -0
  510. package/src/widgets-v2/spread/spread.test.tsx +50 -0
  511. package/src/widgets-v2/spread/spread.tsx +31 -0
  512. package/src/widgets-v2/spread/types.ts +27 -0
  513. package/src/widgets-v2/state/labels.test.ts +33 -0
  514. package/src/widgets-v2/state/labels.ts +20 -0
  515. package/src/widgets-v2/state/style.ts +25 -0
  516. package/src/widgets-v2/state/widget-state.test.tsx +294 -0
  517. package/src/widgets-v2/state/widget-state.tsx +184 -0
  518. package/src/widgets-v2/stores/index.ts +49 -0
  519. package/src/widgets-v2/stores/pipeline-middleware.test.ts +187 -0
  520. package/src/widgets-v2/stores/pipeline-middleware.ts +91 -0
  521. package/src/widgets-v2/stores/transforms.test.ts +162 -0
  522. package/src/widgets-v2/stores/transforms.ts +70 -0
  523. package/src/widgets-v2/stores/types.ts +64 -0
  524. package/src/widgets-v2/stores/use-echart-instance.test.tsx +91 -0
  525. package/src/widgets-v2/stores/use-echart-instance.ts +29 -0
  526. package/src/widgets-v2/stores/use-transform-enabled.test.tsx +127 -0
  527. package/src/widgets-v2/stores/use-transform-enabled.ts +25 -0
  528. package/src/widgets-v2/stores/use-transform.test.tsx +262 -0
  529. package/src/widgets-v2/stores/use-transform.ts +158 -0
  530. package/src/widgets-v2/stores/widget-context.test.tsx +58 -0
  531. package/src/widgets-v2/stores/widget-context.ts +15 -0
  532. package/src/widgets-v2/stores/widget-store-registry.test.ts +292 -0
  533. package/src/widgets-v2/stores/widget-store-registry.ts +248 -0
  534. package/src/widgets-v2/subheader/style.ts +12 -0
  535. package/src/widgets-v2/subheader/subheader.test.tsx +30 -0
  536. package/src/widgets-v2/subheader/subheader.tsx +16 -0
  537. package/src/widgets-v2/table/download.test.ts +75 -0
  538. package/src/widgets-v2/table/download.ts +47 -0
  539. package/src/widgets-v2/table/helpers.test.ts +214 -0
  540. package/src/widgets-v2/table/helpers.ts +136 -0
  541. package/src/widgets-v2/table/index.ts +23 -0
  542. package/src/widgets-v2/table/labels.tsx +41 -0
  543. package/src/widgets-v2/table/skeleton.test.tsx +26 -0
  544. package/src/widgets-v2/table/skeleton.tsx +65 -0
  545. package/src/widgets-v2/table/style.ts +43 -0
  546. package/src/widgets-v2/table/table-ui.test.tsx +200 -0
  547. package/src/widgets-v2/table/table-ui.tsx +364 -0
  548. package/src/widgets-v2/table/table.test.tsx +119 -0
  549. package/src/widgets-v2/table/table.tsx +179 -0
  550. package/src/widgets-v2/table/types.ts +55 -0
  551. package/src/widgets-v2/test-utils.ts +107 -0
  552. package/src/widgets-v2/timeseries/download.test.ts +95 -0
  553. package/src/widgets-v2/timeseries/download.ts +86 -0
  554. package/src/widgets-v2/timeseries/index.ts +10 -0
  555. package/src/widgets-v2/timeseries/options.test.ts +394 -0
  556. package/src/widgets-v2/timeseries/options.ts +348 -0
  557. package/src/widgets-v2/timeseries/skeleton.test.tsx +13 -0
  558. package/src/widgets-v2/timeseries/skeleton.tsx +76 -0
  559. package/src/widgets-v2/timeseries/types.ts +65 -0
  560. package/src/widgets-v2/toolbox/labels.ts +9 -0
  561. package/src/widgets-v2/toolbox/style.ts +33 -0
  562. package/src/widgets-v2/toolbox/toolbox.test.tsx +200 -0
  563. package/src/widgets-v2/toolbox/toolbox.tsx +309 -0
  564. package/src/widgets-v2/types.ts +25 -0
  565. package/src/widgets-v2/utils/data-zoom-layout.ts +26 -0
  566. package/src/widgets-v2/utils/index.ts +3 -0
  567. package/src/widgets-v2/utils/merge-options.test.ts +52 -0
  568. package/src/widgets-v2/utils/merge-options.ts +50 -0
  569. package/src/widgets-v2/utils/resolve-theme-color.test.ts +43 -0
  570. package/src/widgets-v2/utils/resolve-theme-color.ts +34 -0
  571. package/src/widgets-v2/wrapper/index.ts +14 -0
  572. package/src/widgets-v2/wrapper/labels.ts +11 -0
  573. package/src/widgets-v2/wrapper/style.ts +134 -0
  574. package/src/widgets-v2/wrapper/widget-actions.test.tsx +52 -0
  575. package/src/widgets-v2/wrapper/widget-actions.tsx +43 -0
  576. package/src/widgets-v2/wrapper/widget-content.test.tsx +27 -0
  577. package/src/widgets-v2/wrapper/widget-content.tsx +29 -0
  578. package/src/widgets-v2/wrapper/widget-wrapper.test.tsx +159 -0
  579. package/src/widgets-v2/wrapper/widget-wrapper.tsx +178 -0
  580. package/dist/styles-BYTyKQFP.js.map +0 -1
@@ -0,0 +1,107 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { render } from '@testing-library/react'
3
+ import { Series } from './series'
4
+ import { Value } from './value'
5
+ import { Note } from './note'
6
+ import { Prefix } from './prefix'
7
+ import { Suffix } from './suffix'
8
+ import { Delta } from './delta'
9
+
10
+ describe('<Series>', () => {
11
+ it('renders the first letter of name as an Avatar', () => {
12
+ const { getByLabelText } = render(<Series name='Revenue' />)
13
+ const av = getByLabelText('Revenue')
14
+ expect(av.textContent).toBe('R')
15
+ })
16
+
17
+ it('honours a custom size', () => {
18
+ const { getByLabelText } = render(<Series name='Cogs' size={40} />)
19
+ expect(getByLabelText('Cogs')).toBeTruthy()
20
+ })
21
+
22
+ it('passes a CSS colour through unchanged', () => {
23
+ const { getByLabelText } = render(<Series name='X' color='#ff0000' />)
24
+ expect(getByLabelText('X')).toBeTruthy()
25
+ })
26
+
27
+ it('resolves a dotted palette path to a concrete colour via the theme', () => {
28
+ const { getByLabelText } = render(<Series name='Y' color='primary.main' />)
29
+ expect(getByLabelText('Y')).toBeTruthy()
30
+ })
31
+
32
+ it('resolves a nested palette path (palette.warning.dark)', () => {
33
+ const { getByLabelText } = render(<Series name='W' color='warning.dark' />)
34
+ expect(getByLabelText('W')).toBeTruthy()
35
+ })
36
+ })
37
+
38
+ describe('<Value>', () => {
39
+ it('renders children', () => {
40
+ const { getByText } = render(<Value>42</Value>)
41
+ expect(getByText('42')).toBeTruthy()
42
+ })
43
+
44
+ it('applies the supplied color override', () => {
45
+ const { getByText } = render(<Value color='success.main'>ok</Value>)
46
+ expect(getByText('ok')).toBeTruthy()
47
+ })
48
+ })
49
+
50
+ describe('<Note>', () => {
51
+ it('renders children', () => {
52
+ const { getByText } = render(<Note>last 7 days</Note>)
53
+ expect(getByText('last 7 days')).toBeTruthy()
54
+ })
55
+ })
56
+
57
+ describe('<Prefix>', () => {
58
+ it('renders children', () => {
59
+ const { getByText } = render(<Prefix>$</Prefix>)
60
+ expect(getByText('$')).toBeTruthy()
61
+ })
62
+ })
63
+
64
+ describe('<Suffix>', () => {
65
+ it('renders children', () => {
66
+ const { getByText } = render(<Suffix>%</Suffix>)
67
+ expect(getByText('%')).toBeTruthy()
68
+ })
69
+ })
70
+
71
+ describe('<Delta>', () => {
72
+ it('infers positive severity from a positive value', () => {
73
+ const { container } = render(<Delta value={0.12} />)
74
+ // Default percent formatter with signDisplay='always'.
75
+ expect(container.textContent).toContain('+12%')
76
+ expect(container.querySelector('.MuiChip-colorSuccess')).not.toBeNull()
77
+ })
78
+
79
+ it('infers negative severity from a negative value', () => {
80
+ const { container } = render(<Delta value={-0.05} />)
81
+ expect(container.textContent).toContain('-5%')
82
+ expect(container.querySelector('.MuiChip-colorError')).not.toBeNull()
83
+ })
84
+
85
+ it('infers neutral severity from zero', () => {
86
+ const { container } = render(<Delta value={0} />)
87
+ expect(container.textContent).toContain('+0%')
88
+ expect(container.querySelector('.MuiChip-colorDefault')).not.toBeNull()
89
+ })
90
+
91
+ it('renders an explicit label, bypassing the formatter', () => {
92
+ const { getByText } = render(<Delta value={-1} label='down a lot' />)
93
+ expect(getByText('down a lot')).toBeTruthy()
94
+ })
95
+
96
+ it('uses a custom format() when provided', () => {
97
+ const { container } = render(
98
+ <Delta value={3.14} format={(v) => `${v.toFixed(2)}x`} />,
99
+ )
100
+ expect(container.textContent).toContain('3.14x')
101
+ })
102
+
103
+ it('honours an explicit severity override', () => {
104
+ const { container } = render(<Delta value={5} severity='neutral' />)
105
+ expect(container.querySelector('.MuiChip-colorDefault')).not.toBeNull()
106
+ })
107
+ })
@@ -0,0 +1,25 @@
1
+ import { Typography, type TypographyProps } from '@mui/material'
2
+ import type { ReactNode } from 'react'
3
+
4
+ export interface SuffixProps {
5
+ children: ReactNode
6
+ TypographyProps?: TypographyProps
7
+ }
8
+
9
+ /**
10
+ * Suffix slot for a Formula KPI — large, bold, muted (`text.secondary`).
11
+ * Composable building block for custom formula layouts; the canonical
12
+ * {@link FormulaUI} renders one of these per item when `suffix` is set.
13
+ */
14
+ export function Suffix({ children, TypographyProps }: SuffixProps) {
15
+ return (
16
+ <Typography
17
+ variant='h5'
18
+ component='span'
19
+ sx={{ fontWeight: 600, color: 'text.secondary', lineHeight: 1 }}
20
+ {...TypographyProps}
21
+ >
22
+ {children}
23
+ </Typography>
24
+ )
25
+ }
@@ -0,0 +1,48 @@
1
+ import type { WidgetSeries } from '../types'
2
+
3
+ /**
4
+ * Series metadata rendered as a coloured avatar at the start of a row.
5
+ *
6
+ * Type alias of the cross-widget {@link WidgetSeries} shape so the same
7
+ * `{ name, color? }` object can drive Formula avatars, Spread avatars,
8
+ * Category legends, and echart-widget legends with no per-widget shape
9
+ * gymnastics. Kept as a named export for backwards compatibility.
10
+ */
11
+ export type FormulaSeries = WidgetSeries
12
+
13
+ export type DeltaSeverity = 'positive' | 'negative' | 'neutral'
14
+
15
+ /** Comparative delta rendered as a coloured chip on the right of a row. */
16
+ export interface FormulaDelta {
17
+ /** Numeric magnitude. Default formatting renders as a percent (e.g. `-12,3 %`). */
18
+ value: number
19
+ /** Pre-formatted label override (skips the default percent formatter). */
20
+ label?: string
21
+ /**
22
+ * Visual treatment override. When omitted it's derived from `value`'s sign:
23
+ * `>0 → 'positive'`, `<0 → 'negative'`, `=0 → 'neutral'`.
24
+ */
25
+ severity?: DeltaSeverity
26
+ }
27
+
28
+ /** A single KPI value rendered by the Formula widget. */
29
+ export interface FormulaDataItem {
30
+ value: number
31
+ prefix?: string
32
+ suffix?: string
33
+ /** Override the value's text colour (e.g. `'success.main'`). */
34
+ color?: string
35
+ /** Optional series indicator — coloured avatar with first letter of `name`. */
36
+ series?: FormulaSeries
37
+ /** Optional caption rendered below the value. */
38
+ note?: string
39
+ /** Optional comparative delta chip rendered to the right of the row. */
40
+ delta?: FormulaDelta
41
+ }
42
+
43
+ /**
44
+ * Formula widget data — an array of KPI items rendered top-to-bottom. A common
45
+ * "single big number" widget is just `[{ value: 123 }]`. Multi-series usage
46
+ * sets `series`, `note`, and/or `delta` per item.
47
+ */
48
+ export type FormulaWidgetData = readonly FormulaDataItem[]
@@ -0,0 +1,31 @@
1
+ import { Typography, type TypographyProps } from '@mui/material'
2
+ import type { ReactNode } from 'react'
3
+
4
+ export interface ValueProps {
5
+ children: ReactNode
6
+ /** Override the default `text.primary` color — useful for sparkline tints. */
7
+ color?: string
8
+ TypographyProps?: TypographyProps
9
+ }
10
+
11
+ /**
12
+ * Value slot for a Formula KPI — large, bold, primary text color. Composable
13
+ * building block for custom formula layouts; the canonical {@link FormulaUI}
14
+ * renders one of these per item.
15
+ */
16
+ export function Value({ children, color, TypographyProps }: ValueProps) {
17
+ return (
18
+ <Typography
19
+ variant='h5'
20
+ component='span'
21
+ sx={{
22
+ fontWeight: 600,
23
+ color: color ?? 'text.primary',
24
+ lineHeight: 1,
25
+ }}
26
+ {...TypographyProps}
27
+ >
28
+ {children}
29
+ </Typography>
30
+ )
31
+ }
@@ -0,0 +1,94 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest'
2
+ import { createHistogramDownloadConfig } from './download'
3
+ import type { HistogramWidgetData } from './types'
4
+
5
+ const data: HistogramWidgetData = [
6
+ [1, 2, 3],
7
+ [4, 5, 6],
8
+ ]
9
+ const ticks = [0, 10, 20, 30]
10
+
11
+ let csvText = ''
12
+
13
+ beforeEach(() => {
14
+ csvText = ''
15
+ vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock')
16
+ vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined)
17
+ const RealBlob = global.Blob
18
+ vi.stubGlobal(
19
+ 'Blob',
20
+ class extends RealBlob {
21
+ constructor(parts: BlobPart[], opts?: BlobPropertyBag) {
22
+ csvText = typeof parts[0] === 'string' ? parts[0] : ''
23
+ super(parts, opts)
24
+ }
25
+ },
26
+ )
27
+ })
28
+
29
+ describe('createHistogramDownloadConfig', () => {
30
+ it('CSV-only by default', () => {
31
+ const items = createHistogramDownloadConfig({
32
+ filename: 'h',
33
+ getData: () => data,
34
+ getTicks: () => ticks,
35
+ })
36
+ expect(items.map((i) => i.id)).toEqual(['csv'])
37
+ })
38
+
39
+ it('prepends PNG when getCaptureEl is provided', () => {
40
+ const items = createHistogramDownloadConfig({
41
+ filename: 'h',
42
+ getData: () => data,
43
+ getTicks: () => ticks,
44
+ getCaptureEl: () => document.createElement('div'),
45
+ })
46
+ expect(items.map((i) => i.id)).toEqual(['png', 'csv'])
47
+ })
48
+
49
+ it('CSV resolve serialises bins × series with default series names', async () => {
50
+ const items = createHistogramDownloadConfig({
51
+ filename: 'h',
52
+ getData: () => data,
53
+ getTicks: () => ticks,
54
+ })
55
+ const handle = await items.find((i) => i.id === 'csv')!.resolve()
56
+ expect(handle.filename).toBe('h.csv')
57
+ expect(csvText).toBe(
58
+ 'bin_low,bin_high,series_1,series_2\n0,10,1,4\n10,20,2,5\n20,30,3,6',
59
+ )
60
+ })
61
+
62
+ it('CSV honours supplied seriesNames', async () => {
63
+ const items = createHistogramDownloadConfig({
64
+ filename: 'h',
65
+ getData: () => data,
66
+ getTicks: () => ticks,
67
+ seriesNames: ['lo', 'hi'],
68
+ })
69
+ await items.find((i) => i.id === 'csv')!.resolve()
70
+ expect(csvText.startsWith('bin_low,bin_high,lo,hi')).toBe(true)
71
+ })
72
+
73
+ it('CSV emits header-only when ticks has < 2 entries', async () => {
74
+ const items = createHistogramDownloadConfig({
75
+ filename: 'h',
76
+ getData: () => data,
77
+ getTicks: () => [0],
78
+ })
79
+ await items.find((i) => i.id === 'csv')!.resolve()
80
+ expect(csvText).toBe('bin_low,bin_high,series_1,series_2')
81
+ })
82
+
83
+ it('CSV fills missing series values with 0', async () => {
84
+ const sparse: HistogramWidgetData = [[1, 2, 3], []]
85
+ const items = createHistogramDownloadConfig({
86
+ filename: 'h',
87
+ getData: () => sparse,
88
+ getTicks: () => ticks,
89
+ })
90
+ await items.find((i) => i.id === 'csv')!.resolve()
91
+ expect(csvText).toContain('0,10,1,0')
92
+ expect(csvText).toContain('10,20,2,0')
93
+ })
94
+ })
@@ -0,0 +1,60 @@
1
+ import {
2
+ buildPngDownloadItem,
3
+ downloadToCSV,
4
+ type DownloadItem,
5
+ } from '../actions/download'
6
+ import type { HistogramWidgetData } from './types'
7
+
8
+ /**
9
+ * Download menu items for histograms. Always includes a CSV item with
10
+ * `bin_low, bin_high, series_1_count, series_2_count, …` columns (one row
11
+ * per bin). When `getCaptureEl` is supplied, prepends a PNG item that
12
+ * rasterises the captured element via `html2canvas`.
13
+ */
14
+ export function createHistogramDownloadConfig(args: {
15
+ filename: string
16
+ getData: () => HistogramWidgetData
17
+ getTicks: () => readonly number[]
18
+ seriesNames?: readonly string[]
19
+ getCaptureEl?: () => HTMLElement | null
20
+ pngPixelRatio?: number
21
+ pngBackgroundColor?: string | null
22
+ }): DownloadItem[] {
23
+ const items: DownloadItem[] = []
24
+ if (args.getCaptureEl) {
25
+ items.push(
26
+ buildPngDownloadItem({
27
+ filename: args.filename,
28
+ getCaptureEl: args.getCaptureEl,
29
+ pixelRatio: args.pngPixelRatio,
30
+ backgroundColor: args.pngBackgroundColor,
31
+ }),
32
+ )
33
+ }
34
+ items.push({
35
+ id: 'csv',
36
+ label: 'Download as CSV',
37
+ resolve: () => {
38
+ const data = args.getData()
39
+ const ticks = args.getTicks()
40
+ const seriesCount = data.length
41
+ const header: unknown[] = ['bin_low', 'bin_high']
42
+ for (let i = 0; i < seriesCount; i++) {
43
+ header.push(args.seriesNames?.[i] ?? `series_${i + 1}`)
44
+ }
45
+ const rows: unknown[][] = [header]
46
+ for (let bin = 0; bin < Math.max(0, ticks.length - 1); bin++) {
47
+ const row: unknown[] = [ticks[bin], ticks[bin + 1]]
48
+ for (let s = 0; s < seriesCount; s++) row.push(data[s]?.[bin] ?? 0)
49
+ rows.push(row)
50
+ }
51
+ const handle = downloadToCSV(rows)
52
+ return Promise.resolve({
53
+ url: handle.url,
54
+ filename: `${args.filename}.csv`,
55
+ revoke: handle.revoke,
56
+ })
57
+ },
58
+ })
59
+ return items
60
+ }
@@ -0,0 +1,10 @@
1
+ export { histogramOptions, createHistogramOptionFactory } from './options'
2
+ export { HistogramSkeleton, type HistogramSkeletonProps } from './skeleton'
3
+ export { createHistogramDownloadConfig } from './download'
4
+ export { toRelativeHistogramData } from './transforms'
5
+ export type {
6
+ HistogramWidgetData,
7
+ HistogramOptionsInput,
8
+ HistogramOptionFactoryInput,
9
+ HistogramEChartsOption,
10
+ } from './types'
@@ -0,0 +1,318 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { createTheme, type Theme } from '@mui/material'
3
+ import { createHistogramOptionFactory, histogramOptions } from './options'
4
+
5
+ const theme = createTheme() as unknown as Theme
6
+
7
+ describe('histogramOptions (structural)', () => {
8
+ it('returns a category x-axis without baked data', () => {
9
+ const out = histogramOptions({ theme })
10
+ const xAxis = out.xAxis as { type: string; data?: unknown }
11
+ expect(xAxis.type).toBe('category')
12
+ expect(xAxis.data).toBeUndefined()
13
+ })
14
+
15
+ it('returns no series and no dataset (data is fused at render time)', () => {
16
+ const out = histogramOptions({ theme })
17
+ expect(out.series).toBeUndefined()
18
+ expect(out.dataset).toBeUndefined()
19
+ })
20
+
21
+ it('hides x and y axis lines and ticks for the v1 minimal look', () => {
22
+ const out = histogramOptions({ theme })
23
+ const xAxis = out.xAxis as {
24
+ axisLine?: { show?: boolean }
25
+ axisTick?: { show?: boolean }
26
+ }
27
+ const yAxis = out.yAxis as {
28
+ axisLine?: { show?: boolean }
29
+ axisTick?: { show?: boolean }
30
+ splitLine?: { show?: boolean }
31
+ }
32
+ expect(xAxis.axisLine?.show).toBe(false)
33
+ expect(xAxis.axisTick?.show).toBe(false)
34
+ expect(yAxis.axisLine?.show).toBe(false)
35
+ expect(yAxis.axisTick?.show).toBe(false)
36
+ expect(yAxis.splitLine?.show).toBe(true)
37
+ })
38
+
39
+ it('emits a dark themed tooltip with a positioner and a formatter (matches bar)', () => {
40
+ const out = histogramOptions({ theme })
41
+ const tooltip = out.tooltip as {
42
+ backgroundColor?: string
43
+ borderWidth?: number
44
+ position?: unknown
45
+ formatter?: unknown
46
+ textStyle?: { color?: string }
47
+ }
48
+ expect(tooltip.backgroundColor).toBe(theme.palette.grey[900])
49
+ expect(tooltip.borderWidth).toBe(0)
50
+ expect(typeof tooltip.position).toBe('function')
51
+ expect(typeof tooltip.formatter).toBe('function')
52
+ expect(tooltip.textStyle?.color).toBe(theme.palette.common.white)
53
+ })
54
+
55
+ it('emits the CARTO color palette starting with secondary.main', () => {
56
+ const out = histogramOptions({ theme }) as { color?: string[] }
57
+ expect(Array.isArray(out.color)).toBe(true)
58
+ expect(out.color?.[0]).toBe(theme.palette.secondary.main)
59
+ })
60
+
61
+ it('emits a themed axisPointer line', () => {
62
+ const out = histogramOptions({ theme }) as {
63
+ axisPointer?: { lineStyle?: { color?: string } }
64
+ }
65
+ expect(out.axisPointer?.lineStyle?.color).toBe(theme.palette.grey[400])
66
+ })
67
+
68
+ it('renders y-axis labels inside the plot, anchored to the bottom (matches bar)', () => {
69
+ const out = histogramOptions({ theme })
70
+ const yAxis = out.yAxis as {
71
+ axisLabel?: { inside?: boolean; verticalAlign?: string }
72
+ }
73
+ expect(yAxis.axisLabel?.inside).toBe(true)
74
+ expect(yAxis.axisLabel?.verticalAlign).toBe('bottom')
75
+ })
76
+
77
+ it('y-axis min/max are callback closures (niceNum extents), label formatter shows only the extents', () => {
78
+ const fmt = (n: number): string => `${n}k`
79
+ const out = histogramOptions({ theme, formatter: fmt })
80
+ const yAxis = out.yAxis as {
81
+ min?: unknown
82
+ max?: unknown
83
+ axisLabel?: { formatter?: (v: number) => string }
84
+ }
85
+ expect(typeof yAxis.min).toBe('function')
86
+ expect(typeof yAxis.max).toBe('function')
87
+ // niceMin / niceMax default to 0 and 1 until the min/max callbacks run.
88
+ expect(yAxis.axisLabel?.formatter?.(1)).toBe('1k')
89
+ // 0 is suppressed (matches v1/bar) and intermediate values are blanked.
90
+ expect(yAxis.axisLabel?.formatter?.(0)).toBe('')
91
+ expect(yAxis.axisLabel?.formatter?.(0.5)).toBe('')
92
+ })
93
+ })
94
+
95
+ describe('createHistogramOptionFactory (data → dataset merger)', () => {
96
+ it('builds bin labels from consecutive tick pairs', () => {
97
+ const merge = createHistogramOptionFactory({
98
+ theme,
99
+ ticks: [0, 10, 20, 30],
100
+ })
101
+ const out = merge({}, [[5, 10, 3]]) as {
102
+ dataset: { source: [string, number][] }[]
103
+ }
104
+ const labels = out.dataset[0]!.source.map(([label]) => label)
105
+ expect(labels).toEqual(['0–10', '10–20', '20–30'])
106
+ })
107
+
108
+ it('produces one dataset per series with [binLabel, count] tuple rows', () => {
109
+ const merge = createHistogramOptionFactory({
110
+ theme,
111
+ ticks: [0, 10, 20, 30],
112
+ })
113
+ const out = merge({}, [
114
+ [1, 2, 3],
115
+ [10, 20, 30],
116
+ ]) as { dataset: { source: [string, number][] }[]; series: unknown[] }
117
+ expect(out.dataset).toHaveLength(2)
118
+ expect(out.dataset[0]!.source).toEqual([
119
+ ['0–10', 1],
120
+ ['10–20', 2],
121
+ ['20–30', 3],
122
+ ])
123
+ expect(out.dataset[1]!.source).toEqual([
124
+ ['0–10', 10],
125
+ ['10–20', 20],
126
+ ['20–30', 30],
127
+ ])
128
+ expect(out.series).toHaveLength(2)
129
+ })
130
+
131
+ it('encodes columns positionally (x: 0, y: 1) and references each series dataset by index', () => {
132
+ const merge = createHistogramOptionFactory({ theme, ticks: [0, 10] })
133
+ const out = merge({}, [[1], [2]]) as {
134
+ series: {
135
+ type: string
136
+ datasetIndex: number
137
+ encode: { x: number; y: number }
138
+ }[]
139
+ }
140
+ expect(out.series[0]).toMatchObject({
141
+ type: 'bar',
142
+ datasetIndex: 0,
143
+ encode: { x: 0, y: 1 },
144
+ })
145
+ expect(out.series[1]).toMatchObject({
146
+ type: 'bar',
147
+ datasetIndex: 1,
148
+ encode: { x: 0, y: 1 },
149
+ })
150
+ })
151
+
152
+ it('pads short series with 0 to match bin count', () => {
153
+ const merge = createHistogramOptionFactory({
154
+ theme,
155
+ ticks: [0, 10, 20, 30],
156
+ })
157
+ const out = merge({}, [[5]]) as {
158
+ dataset: { source: [string, number][] }[]
159
+ }
160
+ expect(out.dataset[0]!.source.map(([, count]) => count)).toEqual([5, 0, 0])
161
+ })
162
+
163
+ it('attaches an itemStyle.color callback to each series, whether or not a selection is set', () => {
164
+ const merge = createHistogramOptionFactory({
165
+ theme,
166
+ ticks: [0, 10, 20, 30],
167
+ selection: [1],
168
+ })
169
+ const out = merge({}, [[1, 2, 3]]) as {
170
+ series: { itemStyle?: { color?: unknown } }[]
171
+ }
172
+ // The merger ALWAYS emits an `itemStyle.color` callback — when no
173
+ // selection is set, the callback is a passthrough returning the
174
+ // palette color. Always emitting is required so the next setOption
175
+ // overrides the previous callback via normal merge; conditionally
176
+ // dropping the key would let ECharts keep a stale dim callback alive
177
+ // (items would stay dimmed forever after an external clear).
178
+ const noSel = createHistogramOptionFactory({ theme, ticks: [0, 10] })({}, [
179
+ [1],
180
+ ]) as {
181
+ series: { itemStyle?: { color?: unknown } }[]
182
+ }
183
+ expect(typeof noSel.series[0]?.itemStyle?.color).toBe('function')
184
+ expect(typeof out.series[0]?.itemStyle?.color).toBe('function')
185
+ })
186
+
187
+ it('toggles legend.show based on series count (matches bar)', () => {
188
+ const merge = createHistogramOptionFactory({ theme, ticks: [0, 10, 20] })
189
+ const single = merge({}, [[1, 2]]) as { legend?: { show?: boolean } }
190
+ const multi = merge({}, [
191
+ [1, 2],
192
+ [3, 4],
193
+ ]) as { legend?: { show?: boolean } }
194
+ expect(single.legend?.show).toBe(false)
195
+ expect(multi.legend?.show).toBe(true)
196
+ })
197
+
198
+ it('emits a tooltip.formatter function in the merger output', () => {
199
+ const merge = createHistogramOptionFactory({ theme, ticks: [0, 10] })
200
+ const out = merge({}, [[1]]) as {
201
+ tooltip?: { formatter?: unknown }
202
+ }
203
+ expect(typeof out.tooltip?.formatter).toBe('function')
204
+ })
205
+
206
+ it('resolves y-axis min/max to concrete niceNum bounds after fusion', () => {
207
+ const merge = createHistogramOptionFactory({ theme, ticks: [0, 10, 20] })
208
+ const out = merge({}, [[3, 47]]) as {
209
+ yAxis: { min?: number; max?: number }
210
+ }
211
+ expect(out.yAxis.min).toBe(0)
212
+ // 47 → niceNum → 50 (Math.ceil(47 / 10) * 10)
213
+ expect(out.yAxis.max).toBe(50)
214
+ })
215
+
216
+ it('uses series[i].name for series[i].name when provided', () => {
217
+ const merge = createHistogramOptionFactory({
218
+ theme,
219
+ ticks: [0, 10, 20],
220
+ series: [{ name: '2024' }, { name: '2025' }],
221
+ })
222
+ const out = merge({}, [
223
+ [1, 2],
224
+ [3, 4],
225
+ ]) as { series: { name: string }[] }
226
+ expect(out.series[0]?.name).toBe('2024')
227
+ expect(out.series[1]?.name).toBe('2025')
228
+ })
229
+
230
+ it('applies series[i].color as a per-series itemStyle override', () => {
231
+ const merge = createHistogramOptionFactory({
232
+ theme,
233
+ ticks: [0, 10, 20],
234
+ series: [{ name: '2024', color: '#ff0000' }, { name: '2025' }],
235
+ })
236
+ const out = merge({}, [
237
+ [1, 2],
238
+ [3, 4],
239
+ ]) as { series: { color?: string }[] }
240
+ expect(out.series[0]?.color).toBe('#ff0000')
241
+ expect(out.series[1]?.color).toBeUndefined()
242
+ })
243
+
244
+ it('applies labelFormatter to bin labels', () => {
245
+ const merge = createHistogramOptionFactory({
246
+ theme,
247
+ ticks: [0, 10, 20],
248
+ labelFormatter: (s) => `[${s})`,
249
+ })
250
+ const out = merge({}, [[1, 2]]) as {
251
+ dataset: { source: [string, number][] }[]
252
+ }
253
+ expect(out.dataset[0]!.source.map(([label]) => label)).toEqual([
254
+ '[0–10)',
255
+ '[10–20)',
256
+ ])
257
+ })
258
+
259
+ it('returns empty dataset/series when no data', () => {
260
+ const merge = createHistogramOptionFactory({ theme, ticks: [0, 10, 20] })
261
+ const out = merge({ xAxis: { type: 'category' } }, []) as {
262
+ dataset: unknown[]
263
+ series: unknown[]
264
+ }
265
+ expect(out.dataset).toEqual([])
266
+ expect(out.series).toEqual([])
267
+ })
268
+
269
+ describe('tooltip formatter', () => {
270
+ type ItemFormatter = (
271
+ params: unknown,
272
+ ticket?: unknown,
273
+ callback?: unknown,
274
+ ) => string
275
+ const getFormatter = (ctx?: {
276
+ formatter?: (n: number) => string
277
+ }): ItemFormatter => {
278
+ const factory = createHistogramOptionFactory({
279
+ theme,
280
+ ticks: [0, 10, 20],
281
+ })
282
+ const out = factory({}, [[1, 2]], ctx) as {
283
+ tooltip: { formatter: ItemFormatter }
284
+ }
285
+ return out.tooltip.formatter
286
+ }
287
+ const baseItem = {
288
+ seriesName: '2024',
289
+ name: '[0–10)',
290
+ marker: '<i></i>',
291
+ value: ['[0–10)', 5] as [string, number],
292
+ } as const
293
+
294
+ it('reads the count from the value tuple and renders it', () => {
295
+ const html = getFormatter()([baseItem])
296
+ expect(html).toContain('5')
297
+ expect(html).toContain('2024')
298
+ })
299
+
300
+ it('applies the ctx formatter to numeric values', () => {
301
+ const html = getFormatter({ formatter: (n) => `${n}x` })([baseItem])
302
+ expect(html).toContain('5x')
303
+ })
304
+
305
+ it('renders without a series prefix when seriesName is empty', () => {
306
+ const html = getFormatter()([{ ...baseItem, seriesName: '' }])
307
+ expect(html).not.toContain('2024')
308
+ })
309
+
310
+ it('renders an empty value when the tuple is missing', () => {
311
+ const html = getFormatter()([
312
+ { ...baseItem, value: undefined as unknown as [string, number] },
313
+ ])
314
+ // Name still renders even when the value is empty.
315
+ expect(html).toContain('[0–10)')
316
+ })
317
+ })
318
+ })