@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,10 @@
1
+ export { barOptions, createBarOptionFactory } from './options'
2
+ export { BarSkeleton } from './skeleton'
3
+ export { createBarDownloadConfig } from './download'
4
+ export type {
5
+ BarDatum,
6
+ BarWidgetData,
7
+ BarOptionsInput,
8
+ BarOptionFactoryInput,
9
+ BarEChartsOption,
10
+ } from './types'
@@ -0,0 +1,334 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { createTheme, type Theme } from '@mui/material'
3
+ import { barOptions, createBarOptionFactory } from './options'
4
+
5
+ const theme = createTheme() as unknown as Theme
6
+
7
+ describe('barOptions (structural)', () => {
8
+ it('returns a category x-axis without baked data', () => {
9
+ const out = barOptions({ 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 = barOptions({ 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 = barOptions({ 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('y-axis label formatter only renders min/max via the user formatter', () => {
40
+ const fmt = (n: number): string => `$${n}`
41
+ const out = barOptions({ theme, formatter: fmt })
42
+ const yAxis = out.yAxis as {
43
+ axisLabel?: { formatter?: (v: number) => string }
44
+ }
45
+ // niceMin / niceMax default to 0 and 1 until min/max callbacks run.
46
+ expect(yAxis.axisLabel?.formatter?.(1)).toBe('$1')
47
+ // 0 is suppressed (matches v1) and intermediate values are blanked.
48
+ expect(yAxis.axisLabel?.formatter?.(0)).toBe('')
49
+ expect(yAxis.axisLabel?.formatter?.(0.5)).toBe('')
50
+ })
51
+
52
+ it('renders y-axis labels inside the plot, anchored to the bottom', () => {
53
+ const out = barOptions({ theme })
54
+ const yAxis = out.yAxis as {
55
+ axisLabel?: { inside?: boolean; verticalAlign?: string }
56
+ }
57
+ expect(yAxis.axisLabel?.inside).toBe(true)
58
+ expect(yAxis.axisLabel?.verticalAlign).toBe('bottom')
59
+ })
60
+
61
+ it('wires labelFormatter into the x-axis label', () => {
62
+ const lf = (v: string | number) => `[${v}]`
63
+ const out = barOptions({ theme, labelFormatter: lf })
64
+ const xAxis = out.xAxis as {
65
+ axisLabel?: { formatter?: (v: string | number) => string }
66
+ }
67
+ expect(xAxis.axisLabel?.formatter?.('A')).toBe('[A]')
68
+ })
69
+ })
70
+
71
+ describe('createBarOptionFactory', () => {
72
+ it('builds one dataset per series with the data array as source', () => {
73
+ const merge = createBarOptionFactory({ theme })
74
+ const data = [
75
+ [
76
+ { name: 'A', value: 1 },
77
+ { name: 'B', value: 2 },
78
+ ],
79
+ [
80
+ { name: 'A', value: 3 },
81
+ { name: 'B', value: 4 },
82
+ ],
83
+ ]
84
+ const out = merge({}, data) as { dataset: { source: object[] }[] }
85
+ expect(out.dataset).toHaveLength(2)
86
+ expect(out.dataset[0]?.source).toBe(data[0])
87
+ expect(out.dataset[1]?.source).toBe(data[1])
88
+ })
89
+
90
+ it('encodes name → x and value → y, with each series referencing its dataset by index', () => {
91
+ const merge = createBarOptionFactory({ theme })
92
+ const out = merge({}, [
93
+ [{ name: 'A', value: 1 }],
94
+ [{ name: 'A', value: 2 }],
95
+ ]) as {
96
+ series: {
97
+ type: string
98
+ datasetIndex: number
99
+ encode: { x: string; y: string }
100
+ barMaxWidth: number
101
+ emphasis: { focus: string }
102
+ }[]
103
+ }
104
+ expect(out.series[0]).toMatchObject({
105
+ type: 'bar',
106
+ datasetIndex: 0,
107
+ encode: { x: 'name', y: 'value' },
108
+ barMaxWidth: 100,
109
+ emphasis: { focus: 'series' },
110
+ })
111
+ expect(out.series[1]).toMatchObject({
112
+ type: 'bar',
113
+ datasetIndex: 1,
114
+ encode: { x: 'name', y: 'value' },
115
+ barMaxWidth: 100,
116
+ emphasis: { focus: 'series' },
117
+ })
118
+ })
119
+
120
+ it('uses series[i].name for legend names when provided', () => {
121
+ const merge = createBarOptionFactory({
122
+ theme,
123
+ series: [{ name: '2024' }, { name: '2025' }],
124
+ })
125
+ const out = merge({}, [
126
+ [{ name: 'A', value: 1 }],
127
+ [{ name: 'A', value: 2 }],
128
+ ]) as { series: { name: string }[] }
129
+ expect(out.series[0]?.name).toBe('2024')
130
+ expect(out.series[1]?.name).toBe('2025')
131
+ })
132
+
133
+ it('applies series[i].color as a per-series itemStyle override', () => {
134
+ const merge = createBarOptionFactory({
135
+ theme,
136
+ series: [
137
+ { name: '2024', color: '#ff0000' },
138
+ { name: '2025' }, // no color → falls back to palette
139
+ ],
140
+ })
141
+ const out = merge({}, [
142
+ [{ name: 'A', value: 1 }],
143
+ [{ name: 'A', value: 2 }],
144
+ ]) as { series: { color?: string }[] }
145
+ expect(out.series[0]?.color).toBe('#ff0000')
146
+ // Second series has no explicit color → echart palette picks one.
147
+ expect(out.series[1]?.color).toBeUndefined()
148
+ })
149
+
150
+ it('toggles legend visibility based on series count, preserving styling', () => {
151
+ const merge = createBarOptionFactory({ theme })
152
+ const baseLegend = { icon: 'circle', type: 'scroll' }
153
+ const single = merge({ legend: baseLegend }, [
154
+ [{ name: 'A', value: 1 }],
155
+ ]) as { legend: { show: boolean; icon?: string } }
156
+ const multi = merge({ legend: baseLegend }, [
157
+ [{ name: 'A', value: 1 }],
158
+ [{ name: 'A', value: 2 }],
159
+ ]) as { legend: { show: boolean; icon?: string } }
160
+ expect(single.legend.show).toBe(false)
161
+ expect(single.legend.icon).toBe('circle')
162
+ expect(multi.legend.show).toBe(true)
163
+ expect(multi.legend.icon).toBe('circle')
164
+ })
165
+
166
+ it('reserves extra grid bottom space when a legend is shown', () => {
167
+ const merge = createBarOptionFactory({ theme })
168
+ const baseGrid = { bottom: 24 }
169
+ const single = merge({ grid: baseGrid }, [[{ name: 'A', value: 1 }]]) as {
170
+ grid: { bottom: number }
171
+ }
172
+ const multi = merge({ grid: baseGrid }, [
173
+ [{ name: 'A', value: 1 }],
174
+ [{ name: 'A', value: 2 }],
175
+ ]) as { grid: { bottom: number } }
176
+ expect(single.grid.bottom).toBe(24)
177
+ expect(multi.grid.bottom).toBe(56)
178
+ })
179
+
180
+ it('returns empty dataset/series for empty data', () => {
181
+ const merge = createBarOptionFactory({ theme })
182
+ const out = merge({ xAxis: { type: 'category' } }, []) as {
183
+ dataset: unknown[]
184
+ series: unknown[]
185
+ }
186
+ expect(out.dataset).toEqual([])
187
+ expect(out.series).toEqual([])
188
+ })
189
+
190
+ it('merges incoming series template into every series (Stack survives)', () => {
191
+ // Simulates `addStack` having run as a config transform: the option
192
+ // arrives with a single broadcast template carrying { stack: 'total' }.
193
+ const merge = createBarOptionFactory({ theme })
194
+ const out = merge({ series: [{ stack: 'total' }] }, [
195
+ [{ name: 'A', value: 1 }],
196
+ [{ name: 'A', value: 2 }],
197
+ ]) as { series: { stack?: string; type: string; datasetIndex: number }[] }
198
+ expect(out.series).toHaveLength(2)
199
+ expect(out.series[0]?.stack).toBe('total')
200
+ expect(out.series[1]?.stack).toBe('total')
201
+ // Authoritative properties still win over the template.
202
+ expect(out.series[0]?.type).toBe('bar')
203
+ expect(out.series[0]?.datasetIndex).toBe(0)
204
+ expect(out.series[1]?.datasetIndex).toBe(1)
205
+ })
206
+
207
+ it('uses ctx.formatter for the y-axis min/max label (RelativeData support)', () => {
208
+ const merge = createBarOptionFactory({ theme })
209
+ const fmt = (n: number) => `${n}%`
210
+ const out = merge(
211
+ { yAxis: { type: 'value' } },
212
+ [
213
+ [
214
+ { name: 'A', value: 0 },
215
+ { name: 'B', value: 100 },
216
+ ],
217
+ ],
218
+ { formatter: fmt },
219
+ ) as {
220
+ yAxis: {
221
+ min: number
222
+ max: number
223
+ axisLabel: { formatter: (v: number) => string }
224
+ }
225
+ }
226
+ expect(out.yAxis.min).toBe(0)
227
+ expect(out.yAxis.max).toBe(100)
228
+ expect(out.yAxis.axisLabel.formatter(100)).toBe('100%')
229
+ // Intermediate values are still suppressed.
230
+ expect(out.yAxis.axisLabel.formatter(50)).toBe('')
231
+ expect(out.yAxis.axisLabel.formatter(0)).toBe('')
232
+ })
233
+
234
+ it('reserves grid bottom space for the zoom slider when dataZoom is present', () => {
235
+ const merge = createBarOptionFactory({ theme })
236
+ // Single series, no legend.
237
+ const single = merge(
238
+ {
239
+ grid: { bottom: 24 },
240
+ dataZoom: [{ type: 'inside' }, { type: 'slider', bottom: 0 }],
241
+ },
242
+ [[{ name: 'A', value: 1 }]],
243
+ ) as { grid: { bottom: number } }
244
+ // 24 (base) + 32 (slider height) + 8 (gap) = 64.
245
+ expect(single.grid.bottom).toBe(64)
246
+ })
247
+
248
+ it('lifts the zoom slider above the legend when both are present', () => {
249
+ const merge = createBarOptionFactory({ theme })
250
+ const out = merge(
251
+ {
252
+ dataZoom: [{ type: 'inside' }, { type: 'slider', bottom: 0 }],
253
+ },
254
+ [[{ name: 'A', value: 1 }], [{ name: 'A', value: 2 }]],
255
+ ) as {
256
+ dataZoom: { type: string; bottom?: number }[]
257
+ grid: { bottom: number }
258
+ }
259
+ const slider = out.dataZoom.find((d) => d.type === 'slider')
260
+ expect(slider?.bottom).toBe(28)
261
+ // Legend space (56) + slider height (32) + gap (8) = 96.
262
+ expect(out.grid.bottom).toBe(96)
263
+ })
264
+
265
+ describe('itemStyle.color (dim non-selected)', () => {
266
+ it('passes through the params color when no selection is set', () => {
267
+ const merge = createBarOptionFactory({ theme })
268
+ const out = merge({}, [[{ name: 'A', value: 1 }]]) as {
269
+ series: { itemStyle: { color: (p: unknown) => string } }[]
270
+ }
271
+ const colorFn = out.series[0]!.itemStyle.color
272
+ expect(colorFn({ value: { name: 'A' }, color: '#abc', name: 'A' })).toBe(
273
+ '#abc',
274
+ )
275
+ })
276
+
277
+ it('keeps the base colour for bars matching the selection', () => {
278
+ const merge = createBarOptionFactory({ theme, selection: ['A'] })
279
+ const out = merge({}, [[{ name: 'A', value: 1 }]]) as {
280
+ series: { itemStyle: { color: (p: unknown) => string } }[]
281
+ }
282
+ const colorFn = out.series[0]!.itemStyle.color
283
+ expect(colorFn({ value: { name: 'A' }, color: '#abc', name: 'A' })).toBe(
284
+ '#abc',
285
+ )
286
+ })
287
+
288
+ it('dims bars outside the selection via 15% alpha', () => {
289
+ const merge = createBarOptionFactory({ theme, selection: ['B'] })
290
+ const out = merge({}, [[{ name: 'A', value: 1 }]]) as {
291
+ series: { itemStyle: { color: (p: unknown) => string } }[]
292
+ }
293
+ const colorFn = out.series[0]!.itemStyle.color
294
+ const dimmed = colorFn({
295
+ value: { name: 'A' },
296
+ color: '#FF0000',
297
+ name: 'A',
298
+ })
299
+ expect(dimmed).not.toBe('#FF0000')
300
+ })
301
+
302
+ it('falls back to params.name when datum has no name', () => {
303
+ const merge = createBarOptionFactory({ theme, selection: ['A'] })
304
+ const out = merge({}, [[{ name: 'A', value: 1 }]]) as {
305
+ series: { itemStyle: { color: (p: unknown) => string } }[]
306
+ }
307
+ const colorFn = out.series[0]!.itemStyle.color
308
+ expect(colorFn({ value: undefined, color: '#abc', name: 'A' })).toBe(
309
+ '#abc',
310
+ )
311
+ })
312
+ })
313
+
314
+ it('uses ctx formatters for the tooltip (RelativeData support)', () => {
315
+ const merge = createBarOptionFactory({ theme })
316
+ const fmt = (n: number) => `${n}%`
317
+ const lf = (v: string | number) => `[ITEM:${v}]`
318
+ const out = merge({}, [[{ name: 'A', value: 50 }]], {
319
+ formatter: fmt,
320
+ labelFormatter: lf,
321
+ }) as { tooltip: { formatter: (params: unknown) => string } }
322
+ const html = out.tooltip.formatter([
323
+ {
324
+ value: { name: 'A', value: 50 },
325
+ name: 'A',
326
+ seriesName: '',
327
+ marker: '',
328
+ },
329
+ ])
330
+ // The percent formatter and label formatter both ran.
331
+ expect(html).toContain('50%')
332
+ expect(html).toContain('[ITEM:A]')
333
+ })
334
+ })
@@ -0,0 +1,332 @@
1
+ import type { EChartsOption } from 'echarts'
2
+ import * as echarts from 'echarts'
3
+ import type { CallbackDataParams } from 'echarts/types/dist/shared'
4
+ import {
5
+ buildGridConfig,
6
+ buildLegendConfig,
7
+ createTooltipFormatter,
8
+ createTooltipPositioner,
9
+ niceNum,
10
+ } from '../../widgets/utils/chart-config'
11
+ import { ZOOM_LAYOUT } from '../actions/zoom-toggle'
12
+ import type { OptionFactory } from '../echart'
13
+ import { mergeOptions, resolveThemeColor } from '../utils'
14
+ import { positionDataZoomForLegend } from '../utils/data-zoom-layout'
15
+ import type {
16
+ BarEChartsOption,
17
+ BarOptionFactoryInput,
18
+ BarOptionsInput,
19
+ BarWidgetData,
20
+ } from './types'
21
+
22
+ /**
23
+ * Builds the **structural** ECharts option for a bar widget — axes, grid,
24
+ * tooltip styling, themed legend. Intentionally data-agnostic: no series,
25
+ * no dataset, no `legend.show` (those depend on data and are added by the
26
+ * option factory's merge phase). This separation is what lets data-side
27
+ * pipeline transforms (Searcher, RelativeData) drive the rendered chart —
28
+ * the merge happens at render time inside the Echart bridge.
29
+ *
30
+ * Styling matches the v1 `barConfig` look-and-feel: minimal axes (only
31
+ * min/max y-labels rendered inside the plot via `niceNum`), themed tooltip,
32
+ * scroll legend, and CARTO color palette. The y-axis min/max + label
33
+ * formatter and the tooltip formatter are wired here for the no-data case;
34
+ * {@link createBarOptionFactory} re-derives them at fusion time so reactive
35
+ * formatter changes (RelativeData) and stack templates (StackToggle) flow
36
+ * through to the chart.
37
+ */
38
+ export function barOptions({
39
+ theme,
40
+ formatter,
41
+ labelFormatter,
42
+ }: BarOptionsInput): BarEChartsOption {
43
+ // Closure shared between yAxis min/max callbacks and the label formatter,
44
+ // so only the rounded extents are labelled (matches v1).
45
+ let niceMin = 0
46
+ let niceMax = 1
47
+
48
+ return {
49
+ grid: {
50
+ left: parseInt(theme.spacing(1)),
51
+ top: parseInt(theme.spacing(3)),
52
+ right: parseInt(theme.spacing(1)),
53
+ // Default: no legend. Merger bumps this when there are >1 series.
54
+ ...buildGridConfig(false, theme),
55
+ containLabel: true,
56
+ },
57
+ tooltip: {
58
+ trigger: 'axis',
59
+ backgroundColor: theme.palette.grey[900],
60
+ borderWidth: 0,
61
+ padding: [parseInt(theme.spacing(1)), parseInt(theme.spacing(1))],
62
+ textStyle: {
63
+ color: theme.palette.common.white,
64
+ fontSize: 11,
65
+ fontFamily: theme.typography.caption.fontFamily,
66
+ },
67
+ axisPointer: { type: 'line' },
68
+ position: createTooltipPositioner(theme),
69
+ formatter: buildBarTooltipFormatter(formatter, labelFormatter),
70
+ },
71
+ // Legend styling baked here; `show` is toggled by the merger based on
72
+ // series count.
73
+ legend: {
74
+ ...buildLegendConfig({ hasLegend: false, labelFormatter }),
75
+ },
76
+ axisPointer: { lineStyle: { color: theme.palette.grey[400] } },
77
+ color: [
78
+ theme.palette.secondary.main,
79
+ ...Object.values(
80
+ (theme.palette as { qualitative?: { bold?: Record<string, string> } })
81
+ .qualitative?.bold ?? {},
82
+ ),
83
+ ],
84
+ xAxis: {
85
+ type: 'category',
86
+ axisLine: { show: false },
87
+ axisTick: { show: false },
88
+ axisLabel: {
89
+ padding: [parseInt(theme.spacing(0.5)), 0, 0, 0],
90
+ margin: 0,
91
+ hideOverlap: true,
92
+ ...(labelFormatter && {
93
+ formatter: (v: string | number) => String(labelFormatter(v)),
94
+ }),
95
+ },
96
+ },
97
+ yAxis: {
98
+ type: 'value',
99
+ min: (extent: { min: number }) => {
100
+ niceMin = extent.min < 0 ? niceNum(extent.min) : 0
101
+ return niceMin
102
+ },
103
+ max: (extent: { min: number; max: number }) => {
104
+ niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)
105
+ return niceMax
106
+ },
107
+ axisLine: { show: false },
108
+ axisTick: { show: false },
109
+ splitLine: {
110
+ show: true,
111
+ lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },
112
+ },
113
+ axisLabel: {
114
+ fontSize: theme.typography.overlineDelicate?.fontSize,
115
+ fontFamily: theme.typography.overlineDelicate?.fontFamily,
116
+ margin: parseInt(theme.spacing(1)),
117
+ show: true,
118
+ showMaxLabel: true,
119
+ showMinLabel: true,
120
+ verticalAlign: 'bottom',
121
+ inside: true,
122
+ formatter: (value: number) => {
123
+ if (value !== niceMax && value !== niceMin) return ''
124
+ if (value === 0) return ''
125
+ return formatter ? formatter(value) : String(value)
126
+ },
127
+ },
128
+ },
129
+ } as BarEChartsOption
130
+ }
131
+
132
+ /**
133
+ * Returns the bar widget's {@link OptionFactory} — a single closure that
134
+ * handles BOTH option-construction phases:
135
+ *
136
+ * - **Structural phase** (`option == null`) — builds the theme-aware
137
+ * structural option via {@link barOptions}, optionally merging the
138
+ * consumer-supplied `optionsOverride` on top. Called once by Provider
139
+ * to seed `rawOptions` in the store; configTransforms (StackToggle /
140
+ * ZoomToggle / BrushToggle) then mutate it via the pipeline middleware.
141
+ * - **Merge phase** (`option != null`) — fuses post-pipeline `state.data`
142
+ * (`BarWidgetData`) into the option via the dataset API: one dataset
143
+ * per series, each series referencing its dataset by index, encoded
144
+ * by `name` (x) and `value` (y). Spreads any series-template fields
145
+ * already on the incoming option (e.g. `{ stack: 'total' }` from
146
+ * `addStack`) into every emitted series so configTransforms compose
147
+ * end-to-end. Reactive `ctx.formatter` / `ctx.labelFormatter` drive
148
+ * the y-axis min/max-only label and the tooltip formatter at fusion
149
+ * time so RelativeData's percent formatter flows through without a
150
+ * structural rebuild.
151
+ *
152
+ * Stable identity when the inputs don't change (consumers should wrap the
153
+ * call in `useMemo` keyed on the same inputs).
154
+ */
155
+ export function createBarOptionFactory(
156
+ options: BarOptionFactoryInput,
157
+ ): OptionFactory {
158
+ const { theme, formatter, labelFormatter, optionsOverride } = options
159
+ const series = options.series
160
+ const selection = options.selection
161
+ const selectionSet =
162
+ selection && selection.length > 0
163
+ ? new Set<string | number>(selection)
164
+ : null
165
+ return (option, data, ctx) => {
166
+ // Structural phase: Provider seeds rawOptions with this branch. No data
167
+ // is read; we just emit the theme-aware base (optionally with override).
168
+ if (option == null) {
169
+ const structural = barOptions({ theme, formatter, labelFormatter })
170
+ return optionsOverride
171
+ ? (mergeOptions(
172
+ structural as unknown as Record<string, unknown>,
173
+ optionsOverride as Partial<Record<string, unknown>>,
174
+ ) as EChartsOption)
175
+ : structural
176
+ }
177
+
178
+ const seriesArr = Array.isArray(data) ? (data as BarWidgetData) : []
179
+ if (seriesArr.length === 0) {
180
+ return { ...option, dataset: [], series: [] }
181
+ }
182
+ const hasLegend = seriesArr.length > 1
183
+ const baseLegend =
184
+ typeof option.legend === 'object' && !Array.isArray(option.legend)
185
+ ? option.legend
186
+ : {}
187
+ const baseGrid =
188
+ typeof option.grid === 'object' && !Array.isArray(option.grid)
189
+ ? option.grid
190
+ : {}
191
+ const baseTooltip =
192
+ typeof option.tooltip === 'object' && !Array.isArray(option.tooltip)
193
+ ? option.tooltip
194
+ : {}
195
+ const baseYAxis =
196
+ typeof option.yAxis === 'object' && !Array.isArray(option.yAxis)
197
+ ? option.yAxis
198
+ : {}
199
+
200
+ const seriesTemplates = Array.isArray(option.series) ? option.series : []
201
+ const broadcastTemplate = seriesTemplates[0] ?? {}
202
+
203
+ // Reactive (live store) formatters from ctx — distinct from the
204
+ // closure-time `formatter` / `labelFormatter` captured for the
205
+ // structural-build branch above. RelativeData can install a percent
206
+ // formatter on the store after the factory was constructed; the merge
207
+ // phase reads `ctx` to pick that up.
208
+ const liveFormatter = ctx?.formatter
209
+ const liveLabelFormatter = ctx?.labelFormatter
210
+
211
+ const { niceMinVal, niceMaxVal } = computeNiceBounds(seriesArr)
212
+
213
+ // Zoom slider layout: when ZoomToggle has installed `dataZoom`, push the
214
+ // slider above the legend (if any) and reserve room in the grid below.
215
+ const dataZoomLayout = positionDataZoomForLegend(option.dataZoom, hasLegend)
216
+ const fallbackBottom =
217
+ typeof baseGrid.bottom === 'number' ? baseGrid.bottom : 24
218
+ const baseBottom = hasLegend ? 56 : fallbackBottom
219
+ const gridBottom = dataZoomLayout
220
+ ? baseBottom + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap
221
+ : baseBottom
222
+
223
+ // When a selection is active, dim non-selected bars by routing the
224
+ // resolved palette color through `modifyAlpha`. Per-row `itemStyle` on
225
+ // dataset object-rows is silently ignored when `series.encode` is in
226
+ // play — the callback approach is the standard ECharts pattern for
227
+ // per-data styling derived from a dataset.
228
+ //
229
+ // We *always* emit `itemStyle.color` (a passthrough when nothing is
230
+ // selected), not conditionally — dropping the key between renders
231
+ // would let ECharts' default merge keep the previous callback alive
232
+ // and bars would stay dimmed forever after an external clear. Always
233
+ // emitting lets normal merge swap the callback in place, no
234
+ // `replaceMerge` and no entry-animation flash on selection on/off.
235
+ const dimItemStyle = {
236
+ color: (params: CallbackDataParams) => {
237
+ const base = params.color as string
238
+ if (!selectionSet) return base
239
+ const datum = params.value as { name?: string | number } | undefined
240
+ const name = datum?.name ?? params.name
241
+ return name != null && selectionSet.has(name)
242
+ ? base
243
+ : echarts.color.modifyAlpha(base, 0.15)
244
+ },
245
+ }
246
+
247
+ return {
248
+ ...option,
249
+ dataset: seriesArr.map((s) => ({ source: s as readonly object[] })),
250
+ series: seriesArr.map((_, i) => {
251
+ const template =
252
+ (seriesTemplates[i] as object | undefined) ??
253
+ (broadcastTemplate as object)
254
+ // Per-series `color` override: ECharts sets `params.color` from
255
+ // `series[i].color` when resolving styles, so the dim callback
256
+ // above keeps working — it just dims the user's colour rather
257
+ // than the palette default.
258
+ const overrideColor = resolveThemeColor(theme, series?.[i]?.color)
259
+ return {
260
+ ...(typeof template === 'object' ? template : {}),
261
+ type: 'bar' as const,
262
+ datasetIndex: i,
263
+ name: series?.[i]?.name ?? `Series ${i + 1}`,
264
+ encode: { x: 'name', y: 'value' },
265
+ barMaxWidth: 100,
266
+ emphasis: { focus: 'series' },
267
+ itemStyle: dimItemStyle,
268
+ ...(overrideColor ? { color: overrideColor } : {}),
269
+ }
270
+ }),
271
+ legend: { ...baseLegend, show: hasLegend },
272
+ grid: {
273
+ ...baseGrid,
274
+ bottom: gridBottom,
275
+ },
276
+ ...(dataZoomLayout ? { dataZoom: dataZoomLayout } : {}),
277
+ yAxis: {
278
+ ...baseYAxis,
279
+ min: niceMinVal,
280
+ max: niceMaxVal,
281
+ axisLabel: {
282
+ ...((baseYAxis as { axisLabel?: object }).axisLabel ?? {}),
283
+ formatter: (value: number) => {
284
+ if (value !== niceMaxVal && value !== niceMinVal) return ''
285
+ if (value === 0) return ''
286
+ return liveFormatter ? liveFormatter(value) : String(value)
287
+ },
288
+ },
289
+ } as EChartsOption['yAxis'],
290
+ tooltip: {
291
+ ...baseTooltip,
292
+ formatter: buildBarTooltipFormatter(liveFormatter, liveLabelFormatter),
293
+ },
294
+ } as EChartsOption
295
+ }
296
+ }
297
+
298
+ function buildBarTooltipFormatter(
299
+ formatter: ((value: number) => string) | undefined,
300
+ labelFormatter: ((value: string | number) => string | number) | undefined,
301
+ ) {
302
+ return createTooltipFormatter((item) => {
303
+ const row = item.value as { name?: string | number; value?: number }
304
+ const raw = row?.value
305
+ const formattedValue =
306
+ typeof raw === 'number' && formatter ? formatter(raw) : (raw ?? '')
307
+ const marker = typeof item.marker === 'string' ? item.marker : ''
308
+ const seriesName = item.seriesName ? `${item.seriesName}: ` : ''
309
+ const name = labelFormatter
310
+ ? String(labelFormatter(item.name ?? ''))
311
+ : (item.name ?? '')
312
+ return { name: String(name), seriesName, marker, value: formattedValue }
313
+ })
314
+ }
315
+
316
+ function computeNiceBounds(seriesArr: BarWidgetData): {
317
+ niceMinVal: number
318
+ niceMaxVal: number
319
+ } {
320
+ let min = 0
321
+ let max = -Infinity
322
+ for (const series of seriesArr) {
323
+ for (const d of series) {
324
+ if (typeof d?.value !== 'number' || !Number.isFinite(d.value)) continue
325
+ if (d.value < min) min = d.value
326
+ if (d.value > max) max = d.value
327
+ }
328
+ }
329
+ const niceMinVal = min < 0 ? niceNum(min) : 0
330
+ const niceMaxVal = max <= 0 ? 1 : niceNum(max)
331
+ return { niceMinVal, niceMaxVal }
332
+ }
@@ -0,0 +1,19 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { render } from '@testing-library/react'
3
+ import { BarSkeleton } from './skeleton'
4
+
5
+ describe('<BarSkeleton>', () => {
6
+ it('renders without crashing', () => {
7
+ const { container } = render(<BarSkeleton />)
8
+ expect(container.firstChild).not.toBeNull()
9
+ })
10
+
11
+ it('renders MUI Skeleton placeholders for the bars + axis', () => {
12
+ const { container } = render(<BarSkeleton />)
13
+ // MuiSkeleton applies the .MuiSkeleton-root class — count > 1 confirms
14
+ // both the bar grid AND the axis row are emitted.
15
+ expect(
16
+ container.querySelectorAll('.MuiSkeleton-root').length,
17
+ ).toBeGreaterThan(1)
18
+ })
19
+ })