@carto/ps-react-ui 4.3.3 → 4.3.5

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 (301) hide show
  1. package/dist/components.js +3 -3
  2. package/dist/components.js.map +1 -1
  3. package/dist/{lasso-tool-BwRzEW7k.js → lasso-tool-wFqOD6wk.js} +13 -13
  4. package/dist/lasso-tool-wFqOD6wk.js.map +1 -0
  5. package/dist/types/components/common-types.d.ts +41 -0
  6. package/dist/types/components/types.d.ts +1 -1
  7. package/dist/types/widgets/echart/echart-ui.d.ts +1 -1
  8. package/dist/types/widgets/echart/types.d.ts +4 -0
  9. package/dist/widgets/actions.js +1 -1
  10. package/dist/widgets/bar.js +1 -1
  11. package/dist/widgets/category.js +1 -1
  12. package/dist/widgets/echart.js +96 -85
  13. package/dist/widgets/echart.js.map +1 -1
  14. package/dist/widgets/formula.js +1 -1
  15. package/dist/widgets/histogram.js +1 -1
  16. package/dist/widgets/markdown.js +1 -1
  17. package/dist/widgets/pie.js +1 -1
  18. package/dist/widgets/scatterplot.js +1 -1
  19. package/dist/widgets/spread.js +1 -1
  20. package/dist/widgets/table.js +1 -1
  21. package/dist/widgets/timeseries.js +1 -1
  22. package/dist/widgets/toolbar-actions.js.map +1 -1
  23. package/dist/widgets/wrapper.js +1 -1
  24. package/package.json +8 -3
  25. package/src/components/basemaps/basemaps.test.tsx +196 -0
  26. package/src/components/basemaps/basemaps.tsx +128 -0
  27. package/src/components/basemaps/const.ts +13 -0
  28. package/src/components/basemaps/group-wrapper.test.tsx +38 -0
  29. package/src/components/basemaps/group-wrapper.tsx +28 -0
  30. package/src/components/basemaps/group.test.tsx +52 -0
  31. package/src/components/basemaps/group.tsx +42 -0
  32. package/src/components/basemaps/header.test.tsx +54 -0
  33. package/src/components/basemaps/header.tsx +36 -0
  34. package/src/components/basemaps/styles.ts +76 -0
  35. package/src/components/basemaps/types.ts +30 -0
  36. package/src/components/common-types.ts +1 -0
  37. package/src/components/geolocation-controls/const.ts +6 -0
  38. package/src/components/geolocation-controls/geolocation-controls.test.tsx +133 -0
  39. package/src/components/geolocation-controls/geolocation-controls.tsx +95 -0
  40. package/src/components/geolocation-controls/types.ts +17 -0
  41. package/src/components/index.ts +64 -0
  42. package/src/components/lasso-tool/chip.tsx +37 -0
  43. package/src/components/lasso-tool/const.tsx +70 -0
  44. package/src/components/lasso-tool/icons.tsx +91 -0
  45. package/src/components/lasso-tool/lasso-tool-inline.test.tsx +168 -0
  46. package/src/components/lasso-tool/lasso-tool-inline.tsx +245 -0
  47. package/src/components/lasso-tool/lasso-tool.test.tsx +212 -0
  48. package/src/components/lasso-tool/lasso-tool.tsx +479 -0
  49. package/src/components/lasso-tool/styles.ts +143 -0
  50. package/src/components/lasso-tool/types.ts +114 -0
  51. package/src/components/list-data/list-data-skeleton.test.tsx +10 -0
  52. package/src/components/list-data/list-data-skeleton.tsx +40 -0
  53. package/src/components/list-data/list-data.test.tsx +94 -0
  54. package/src/components/list-data/list-data.tsx +106 -0
  55. package/src/components/list-data/styles.ts +37 -0
  56. package/src/components/list-data/types.ts +25 -0
  57. package/src/components/measurement-tools/const.tsx +108 -0
  58. package/src/components/measurement-tools/icons.tsx +54 -0
  59. package/src/components/measurement-tools/measurement-tools.test.tsx +165 -0
  60. package/src/components/measurement-tools/measurement-tools.tsx +443 -0
  61. package/src/components/measurement-tools/styles.ts +91 -0
  62. package/src/components/measurement-tools/types.ts +77 -0
  63. package/src/components/no-data-alert/no-data-alert.test.tsx +31 -0
  64. package/src/components/no-data-alert/no-data-alert.tsx +59 -0
  65. package/src/components/responsive-drawer/responsive-drawer.test.tsx +91 -0
  66. package/src/components/responsive-drawer/responsive-drawer.tsx +53 -0
  67. package/src/components/smart-tooltip/smart-tooltip.test.tsx +168 -0
  68. package/src/components/smart-tooltip/smart-tooltip.tsx +40 -0
  69. package/src/components/tooltip/tooltip.test.tsx +86 -0
  70. package/src/components/tooltip/tooltip.tsx +30 -0
  71. package/src/components/types.ts +1 -0
  72. package/src/components/zoom-controls/styles.ts +27 -0
  73. package/src/components/zoom-controls/types.ts +19 -0
  74. package/src/components/zoom-controls/zoom-controls.test.tsx +101 -0
  75. package/src/components/zoom-controls/zoom-controls.tsx +114 -0
  76. package/src/hooks/index.ts +2 -0
  77. package/src/hooks/use-debounce.ts +55 -0
  78. package/src/hooks/use-skeleton.test.tsx +32 -0
  79. package/src/hooks/use-skeleton.ts +19 -0
  80. package/src/hooks/use-widget-ref.ts +33 -0
  81. package/src/widgets/README.md +277 -0
  82. package/src/widgets/_shared/chart-config/config-factory.ts +67 -0
  83. package/src/widgets/_shared/chart-config/csv-modifiers.ts +56 -0
  84. package/src/widgets/_shared/chart-config/index.ts +21 -0
  85. package/src/widgets/_shared/chart-config/option-builders.ts +203 -0
  86. package/src/widgets/_shared/skeleton/index.ts +5 -0
  87. package/src/widgets/_shared/skeleton/styles.ts +20 -0
  88. package/src/widgets/actions/change-column/change-column-icon.tsx +10 -0
  89. package/src/widgets/actions/change-column/change-column.test.tsx +163 -0
  90. package/src/widgets/actions/change-column/change-column.tsx +141 -0
  91. package/src/widgets/actions/change-column/sortable-column-item.tsx +49 -0
  92. package/src/widgets/actions/change-column/types.ts +20 -0
  93. package/src/widgets/actions/download/download.test.tsx +322 -0
  94. package/src/widgets/actions/download/download.tsx +118 -0
  95. package/src/widgets/actions/download/exports.test.tsx +275 -0
  96. package/src/widgets/actions/download/exports.tsx +103 -0
  97. package/src/widgets/actions/download/types.ts +21 -0
  98. package/src/widgets/actions/fullscreen/fullscreen.test.tsx +269 -0
  99. package/src/widgets/actions/fullscreen/fullscreen.tsx +82 -0
  100. package/src/widgets/actions/fullscreen/styles.ts +17 -0
  101. package/src/widgets/actions/fullscreen/types.ts +27 -0
  102. package/src/widgets/actions/index.ts +51 -0
  103. package/src/widgets/actions/lock-selection/lock-selection.test.tsx +186 -0
  104. package/src/widgets/actions/lock-selection/lock-selection.tsx +133 -0
  105. package/src/widgets/actions/lock-selection/types.ts +41 -0
  106. package/src/widgets/actions/relative-data/relative-data.test.tsx +267 -0
  107. package/src/widgets/actions/relative-data/relative-data.tsx +133 -0
  108. package/src/widgets/actions/relative-data/style.ts +9 -0
  109. package/src/widgets/actions/relative-data/types.ts +31 -0
  110. package/src/widgets/actions/relative-data/utils.test.ts +223 -0
  111. package/src/widgets/actions/relative-data/utils.ts +58 -0
  112. package/src/widgets/actions/searcher/searcher-toggle.test.tsx +354 -0
  113. package/src/widgets/actions/searcher/searcher-toggle.tsx +73 -0
  114. package/src/widgets/actions/searcher/searcher.tsx +205 -0
  115. package/src/widgets/actions/searcher/types.ts +72 -0
  116. package/src/widgets/actions/shared/styles.ts +12 -0
  117. package/src/widgets/actions/stack-toggle/grouped-bar-chart-icon.tsx +14 -0
  118. package/src/widgets/actions/stack-toggle/stack-toggle.test.tsx +270 -0
  119. package/src/widgets/actions/stack-toggle/stack-toggle.tsx +146 -0
  120. package/src/widgets/actions/stack-toggle/types.ts +29 -0
  121. package/src/widgets/actions/zoom-toggle/index.ts +2 -0
  122. package/src/widgets/actions/zoom-toggle/style.ts +14 -0
  123. package/src/widgets/actions/zoom-toggle/types.ts +44 -0
  124. package/src/widgets/actions/zoom-toggle/zoom-toggle.tsx +186 -0
  125. package/src/widgets/bar/config.ts +122 -0
  126. package/src/widgets/bar/index.ts +9 -0
  127. package/src/widgets/bar/skeleton.tsx +60 -0
  128. package/src/widgets/bar/style.ts +33 -0
  129. package/src/widgets/bar/types.ts +16 -0
  130. package/src/widgets/category/category-ui.test.tsx +399 -0
  131. package/src/widgets/category/category-ui.tsx +156 -0
  132. package/src/widgets/category/components/category-bar.tsx +28 -0
  133. package/src/widgets/category/components/category-legend.tsx +30 -0
  134. package/src/widgets/category/components/category-row-multi.tsx +50 -0
  135. package/src/widgets/category/components/category-row-other.tsx +23 -0
  136. package/src/widgets/category/components/category-row-single.tsx +47 -0
  137. package/src/widgets/category/components/index.ts +14 -0
  138. package/src/widgets/category/config.ts +85 -0
  139. package/src/widgets/category/index.ts +30 -0
  140. package/src/widgets/category/skeleton.tsx +24 -0
  141. package/src/widgets/category/style.ts +133 -0
  142. package/src/widgets/category/types.ts +40 -0
  143. package/src/widgets/echart/const.ts +1 -0
  144. package/src/widgets/echart/echart-ui.test.tsx +537 -0
  145. package/src/widgets/echart/echart-ui.tsx +92 -0
  146. package/src/widgets/echart/echart.test.tsx +562 -0
  147. package/src/widgets/echart/echart.tsx +68 -0
  148. package/src/widgets/echart/index.ts +16 -0
  149. package/src/widgets/echart/options.ts +53 -0
  150. package/src/widgets/echart/types.ts +45 -0
  151. package/src/widgets/echart/utils.ts +169 -0
  152. package/src/widgets/error/error.test.tsx +331 -0
  153. package/src/widgets/error/error.tsx +40 -0
  154. package/src/widgets/error/index.ts +2 -0
  155. package/src/widgets/error/types.ts +14 -0
  156. package/src/widgets/formula/components/item.test.tsx +249 -0
  157. package/src/widgets/formula/components/item.tsx +18 -0
  158. package/src/widgets/formula/components/prefix.test.tsx +341 -0
  159. package/src/widgets/formula/components/prefix.tsx +18 -0
  160. package/src/widgets/formula/components/row.test.tsx +364 -0
  161. package/src/widgets/formula/components/row.tsx +21 -0
  162. package/src/widgets/formula/components/series.tsx +34 -0
  163. package/src/widgets/formula/components/suffix.test.tsx +383 -0
  164. package/src/widgets/formula/components/suffix.tsx +28 -0
  165. package/src/widgets/formula/components/value.test.tsx +329 -0
  166. package/src/widgets/formula/components/value.tsx +29 -0
  167. package/src/widgets/formula/config.ts +27 -0
  168. package/src/widgets/formula/formula-ui.test.tsx +399 -0
  169. package/src/widgets/formula/formula-ui.tsx +27 -0
  170. package/src/widgets/formula/index.ts +24 -0
  171. package/src/widgets/formula/serializer.test.tsx +144 -0
  172. package/src/widgets/formula/serializer.ts +28 -0
  173. package/src/widgets/formula/skeleton.tsx +10 -0
  174. package/src/widgets/formula/style.ts +23 -0
  175. package/src/widgets/formula/types.ts +50 -0
  176. package/src/widgets/histogram/config.ts +143 -0
  177. package/src/widgets/histogram/index.ts +8 -0
  178. package/src/widgets/histogram/skeleton.tsx +52 -0
  179. package/src/widgets/histogram/style.ts +8 -0
  180. package/src/widgets/histogram/types.ts +17 -0
  181. package/src/widgets/index.ts +25 -0
  182. package/src/widgets/loader/index.ts +4 -0
  183. package/src/widgets/loader/loader.tsx +70 -0
  184. package/src/widgets/loader/types.ts +11 -0
  185. package/src/widgets/loader/utils.test.ts +112 -0
  186. package/src/widgets/loader/utils.ts +35 -0
  187. package/src/widgets/markdown/config.ts +18 -0
  188. package/src/widgets/markdown/index.ts +14 -0
  189. package/src/widgets/markdown/markdown-ui.test.tsx +341 -0
  190. package/src/widgets/markdown/markdown-ui.tsx +52 -0
  191. package/src/widgets/markdown/markdown.tsx +20 -0
  192. package/src/widgets/markdown/skeleton.tsx +12 -0
  193. package/src/widgets/markdown/style.ts +28 -0
  194. package/src/widgets/markdown/types.ts +28 -0
  195. package/src/widgets/no-data/index.ts +2 -0
  196. package/src/widgets/no-data/no-data.test.tsx +447 -0
  197. package/src/widgets/no-data/no-data.tsx +116 -0
  198. package/src/widgets/no-data/style.ts +18 -0
  199. package/src/widgets/no-data/types.ts +72 -0
  200. package/src/widgets/note/index.ts +2 -0
  201. package/src/widgets/note/note.test.tsx +391 -0
  202. package/src/widgets/note/note.tsx +114 -0
  203. package/src/widgets/note/style.ts +29 -0
  204. package/src/widgets/note/types.ts +9 -0
  205. package/src/widgets/pie/config.ts +177 -0
  206. package/src/widgets/pie/index.ts +8 -0
  207. package/src/widgets/pie/skeleton.tsx +70 -0
  208. package/src/widgets/pie/style.ts +8 -0
  209. package/src/widgets/pie/types.ts +16 -0
  210. package/src/widgets/range/components/range-item.tsx +213 -0
  211. package/src/widgets/range/config.ts +10 -0
  212. package/src/widgets/range/index.ts +16 -0
  213. package/src/widgets/range/range-ui.test.tsx +203 -0
  214. package/src/widgets/range/range-ui.tsx +11 -0
  215. package/src/widgets/range/serializer.test.ts +70 -0
  216. package/src/widgets/range/serializer.ts +27 -0
  217. package/src/widgets/range/skeleton.tsx +14 -0
  218. package/src/widgets/range/style.ts +37 -0
  219. package/src/widgets/range/types.ts +39 -0
  220. package/src/widgets/scatterplot/config.ts +138 -0
  221. package/src/widgets/scatterplot/index.ts +8 -0
  222. package/src/widgets/scatterplot/skeleton.tsx +59 -0
  223. package/src/widgets/scatterplot/style.ts +21 -0
  224. package/src/widgets/scatterplot/types.ts +17 -0
  225. package/src/widgets/selection-summary/index.ts +6 -0
  226. package/src/widgets/selection-summary/selection-summary.tsx +46 -0
  227. package/src/widgets/selection-summary/style.ts +10 -0
  228. package/src/widgets/selection-summary/types.ts +14 -0
  229. package/src/widgets/skeleton-loader/index.ts +2 -0
  230. package/src/widgets/skeleton-loader/skeleton-loader.test.tsx +139 -0
  231. package/src/widgets/skeleton-loader/skeleton-loader.tsx +28 -0
  232. package/src/widgets/skeleton-loader/types.ts +8 -0
  233. package/src/widgets/spread/components/max-value.tsx +29 -0
  234. package/src/widgets/spread/components/min-value.tsx +29 -0
  235. package/src/widgets/spread/components/separator.tsx +6 -0
  236. package/src/widgets/spread/config.ts +34 -0
  237. package/src/widgets/spread/index.ts +23 -0
  238. package/src/widgets/spread/skeleton.tsx +10 -0
  239. package/src/widgets/spread/spread-ui.test.tsx +368 -0
  240. package/src/widgets/spread/spread-ui.tsx +29 -0
  241. package/src/widgets/spread/style.ts +22 -0
  242. package/src/widgets/spread/types.ts +47 -0
  243. package/src/widgets/stores/index.ts +9 -0
  244. package/src/widgets/stores/types.ts +192 -0
  245. package/src/widgets/stores/widget-store.test.ts +601 -0
  246. package/src/widgets/stores/widget-store.ts +239 -0
  247. package/src/widgets/subheader/index.ts +3 -0
  248. package/src/widgets/subheader/style.ts +20 -0
  249. package/src/widgets/subheader/subheader.test.tsx +45 -0
  250. package/src/widgets/subheader/subheader.tsx +16 -0
  251. package/src/widgets/subheader/types.ts +11 -0
  252. package/src/widgets/table/components/cell-header.tsx +58 -0
  253. package/src/widgets/table/components/cell.tsx +80 -0
  254. package/src/widgets/table/components/index.ts +4 -0
  255. package/src/widgets/table/components/pagination-actions.tsx +67 -0
  256. package/src/widgets/table/components/pagination.tsx +41 -0
  257. package/src/widgets/table/components/row.tsx +60 -0
  258. package/src/widgets/table/config.ts +71 -0
  259. package/src/widgets/table/helpers.test.ts +244 -0
  260. package/src/widgets/table/helpers.ts +107 -0
  261. package/src/widgets/table/hooks/index.ts +7 -0
  262. package/src/widgets/table/hooks/use-pagination.test.ts +294 -0
  263. package/src/widgets/table/hooks/use-pagination.ts +155 -0
  264. package/src/widgets/table/hooks/use-selection.test.ts +504 -0
  265. package/src/widgets/table/hooks/use-selection.ts +189 -0
  266. package/src/widgets/table/hooks/use-sort.test.ts +296 -0
  267. package/src/widgets/table/hooks/use-sort.ts +138 -0
  268. package/src/widgets/table/index.ts +53 -0
  269. package/src/widgets/table/serializer.ts +54 -0
  270. package/src/widgets/table/skeleton.tsx +48 -0
  271. package/src/widgets/table/style.ts +34 -0
  272. package/src/widgets/table/table-ui.tsx +64 -0
  273. package/src/widgets/table/types.ts +223 -0
  274. package/src/widgets/timeseries/config.ts +135 -0
  275. package/src/widgets/timeseries/index.ts +8 -0
  276. package/src/widgets/timeseries/skeleton.tsx +55 -0
  277. package/src/widgets/timeseries/style.ts +36 -0
  278. package/src/widgets/timeseries/types.ts +17 -0
  279. package/src/widgets/toolbar-actions/index.ts +6 -0
  280. package/src/widgets/toolbar-actions/styles.ts +38 -0
  281. package/src/widgets/toolbar-actions/toolbar-actions.test.tsx +691 -0
  282. package/src/widgets/toolbar-actions/toolbar-actions.tsx +145 -0
  283. package/src/widgets/toolbar-actions/types.ts +60 -0
  284. package/src/widgets/wrapper/components/actions.test.tsx +101 -0
  285. package/src/widgets/wrapper/components/actions.tsx +30 -0
  286. package/src/widgets/wrapper/components/options.test.tsx +323 -0
  287. package/src/widgets/wrapper/components/options.tsx +73 -0
  288. package/src/widgets/wrapper/components/title.test.tsx +126 -0
  289. package/src/widgets/wrapper/components/title.tsx +32 -0
  290. package/src/widgets/wrapper/index.ts +16 -0
  291. package/src/widgets/wrapper/styles.ts +98 -0
  292. package/src/widgets/wrapper/types.ts +55 -0
  293. package/src/widgets/wrapper/wrapper-ui.test.tsx +232 -0
  294. package/src/widgets/wrapper/wrapper-ui.tsx +57 -0
  295. package/src/widgets/wrapper/wrapper.test.tsx +365 -0
  296. package/src/widgets/wrapper/wrapper.tsx +50 -0
  297. package/dist/lasso-tool-BwRzEW7k.js.map +0 -1
  298. package/dist/types/common/common.d.ts +0 -3
  299. package/dist/types/common/index.d.ts +0 -26
  300. package/dist/types/common/lasso-tools.d.ts +0 -36
  301. package/dist/types/common/measurement-tools.d.ts +0 -65
@@ -0,0 +1,50 @@
1
+ import type { TypographyProps } from '@mui/material'
2
+ import type { ReactNode } from 'react'
3
+ import type { BaseWidgetState, WidgetsStoreProps } from '../stores/types'
4
+ import type { WrapperState } from '../wrapper/types'
5
+ import type { DownloadItem } from '../actions/download/types'
6
+
7
+ export interface FormulaUIProps {
8
+ id: WidgetsStoreProps['id']
9
+ }
10
+
11
+ export interface DataItem {
12
+ value: number
13
+ prefix?: string | ReactNode
14
+ suffix?: string | ReactNode
15
+ color?: string
16
+ }
17
+
18
+ export interface RowProps {
19
+ id: WidgetsStoreProps['id']
20
+ children: ReactNode | ((props: { index: number }) => ReactNode)
21
+ }
22
+
23
+ export interface ValueProps extends Omit<ItemProps, 'children'> {
24
+ id: WidgetsStoreProps['id']
25
+ index?: number
26
+ }
27
+
28
+ export interface ItemProps {
29
+ children: ReactNode
30
+ disabled?: boolean
31
+ TypographyProps?: TypographyProps
32
+ }
33
+
34
+ export type FormulaWidgetData = DataItem[]
35
+
36
+ export interface SeriesConfig {
37
+ name: string
38
+ color?: string
39
+ }
40
+
41
+ export type FormulaWidgetState = BaseWidgetState<
42
+ WrapperState<FormulaWidgetConfig> & { data: FormulaWidgetData }
43
+ >
44
+
45
+ export interface FormulaWidgetConfig {
46
+ formatter?: (value: number) => string
47
+ series?: SeriesConfig[]
48
+ }
49
+
50
+ export type FormulaDownloadConfig = DownloadItem<FormulaWidgetData>[]
@@ -0,0 +1,143 @@
1
+ import {
2
+ getCommonOptions,
3
+ mergeEchartWidgetConfig,
4
+ type EchartOptionsProps,
5
+ } from '../echart'
6
+ import type {
7
+ HistogramConfig,
8
+ HistogramWidgetConfig,
9
+ HistogramWidgetData,
10
+ } from './types'
11
+ import {
12
+ flattenObjectArrayToCSV,
13
+ buildLegendConfig,
14
+ buildGridConfig,
15
+ createTooltipPositioner,
16
+ createTooltipFormatter,
17
+ applyYAxisFormatter,
18
+ } from '../_shared/chart-config'
19
+ import { downloadToCSV, downloadToPNG, type DownloadItem } from '../actions'
20
+ import type { ConfigProps } from '../loader/types'
21
+
22
+ export function histogramDownloadConfig({
23
+ refUI,
24
+ }: ConfigProps): DownloadItem<HistogramWidgetData>[] {
25
+ return [
26
+ {
27
+ ...downloadToPNG,
28
+ modifier: () => downloadToPNG.modifier(refUI),
29
+ },
30
+ {
31
+ ...downloadToCSV,
32
+ modifier: async (data) => {
33
+ const rows = flattenObjectArrayToCSV(data)
34
+ return downloadToCSV.modifier(rows)
35
+ },
36
+ },
37
+ ]
38
+ }
39
+ export function histogramConfig(props: HistogramConfig): HistogramWidgetConfig {
40
+ return {
41
+ type: 'histogram',
42
+ option: mergeEchartWidgetConfig(getCommonOptions(props), getOption(props)),
43
+ }
44
+ }
45
+ function getOption({
46
+ data = [],
47
+ theme,
48
+ formatter,
49
+ }: HistogramConfig): EchartOptionsProps {
50
+ const hasLegend = (data?.length ?? 0) > 1
51
+
52
+ const yAxis = {
53
+ type: 'value' as const,
54
+ showMaxLabel: true,
55
+ showMinLabel: true,
56
+ splitNumber: 1,
57
+ axisLabel: {
58
+ fontSize: theme.typography.overlineDelicate.fontSize,
59
+ fontFamily: theme.typography.overlineDelicate.fontFamily,
60
+ margin: parseInt(theme.spacing(1)),
61
+ show: true,
62
+ showMaxLabel: true,
63
+ showMinLabel: true,
64
+ verticalAlign: 'bottom' as const,
65
+ },
66
+ axisLine: {
67
+ show: false,
68
+ },
69
+ axisTick: {
70
+ show: false,
71
+ },
72
+ splitLine: {
73
+ show: true,
74
+ lineStyle: {
75
+ color: theme.palette.black[4],
76
+ },
77
+ },
78
+ }
79
+
80
+ return {
81
+ legend: buildLegendConfig(hasLegend),
82
+ grid: buildGridConfig(hasLegend, theme),
83
+ xAxis: {
84
+ type: 'category',
85
+ axisLine: {
86
+ show: false,
87
+ },
88
+ axisLabel: {
89
+ fontSize: theme.typography.overlineDelicate.fontSize,
90
+ fontFamily: theme.typography.overlineDelicate.fontFamily,
91
+ showMinLabel: true,
92
+ showMaxLabel: true,
93
+ hideOverlap: true,
94
+ margin: 0,
95
+ padding: [
96
+ parseInt(theme.spacing(0.5)),
97
+ parseInt(theme.spacing(0.5)),
98
+ 0,
99
+ parseInt(theme.spacing(0.5)),
100
+ ],
101
+ color: theme.palette.black[60],
102
+ },
103
+ axisTick: {
104
+ show: false,
105
+ },
106
+ splitLine: {
107
+ show: true,
108
+ lineStyle: {
109
+ color: theme.palette.black[4],
110
+ },
111
+ },
112
+ },
113
+ yAxis: applyYAxisFormatter(yAxis, formatter),
114
+ tooltip: {
115
+ position: createTooltipPositioner(theme),
116
+ formatter: createTooltipFormatter((item) => {
117
+ const value = item.value as Record<string, string | number>
118
+ const index = item.dimensionNames?.[item.encode?.y?.at(0) ?? 1]
119
+ const _value = value[index ?? '']
120
+
121
+ const formattedValue =
122
+ typeof _value === 'number' && formatter
123
+ ? formatter(_value)
124
+ : (_value ?? '')
125
+
126
+ const marker = typeof item.marker === 'string' ? item.marker : ''
127
+ const seriesName = item.seriesName ? `${item.seriesName}: ` : ''
128
+ const name = item.name ?? ''
129
+
130
+ return { name, seriesName, marker, value: formattedValue }
131
+ }),
132
+ },
133
+ series: data.map((_: unknown, index: number) => ({
134
+ datasetIndex: index,
135
+ type: 'bar',
136
+ barGap: '1%', // No gap between bars in histogram
137
+ barCategoryGap: '1%', // No gap between categories in histogram
138
+ emphasis: {
139
+ focus: 'series',
140
+ },
141
+ })),
142
+ } as EchartOptionsProps
143
+ }
@@ -0,0 +1,8 @@
1
+ export type {
2
+ HistogramConfig,
3
+ HistogramWidgetConfig,
4
+ HistogramWidgetData,
5
+ HistogramWidgetState,
6
+ } from './types'
7
+ export { histogramConfig, histogramDownloadConfig } from './config'
8
+ export { HistogramSkeleton } from './skeleton'
@@ -0,0 +1,52 @@
1
+ import { Box, Skeleton } from '@mui/material'
2
+ import { styles } from './style'
3
+
4
+ export function HistogramSkeleton() {
5
+ return (
6
+ <Box sx={styles.skeleton.graph.container}>
7
+ <Box
8
+ sx={{
9
+ display: 'flex',
10
+ alignItems: 'flex-end',
11
+ justifyContent: 'space-between',
12
+ gap: ({ spacing }) => spacing(0.5),
13
+ height: ({ spacing }) => spacing(30),
14
+ width: '100%',
15
+ }}
16
+ >
17
+ {Array(8)
18
+ .fill(0)
19
+ .map((_, i) => {
20
+ // Create varying heights for histogram bars
21
+ const heights = [60, 80, 95, 85, 70, 55, 40, 30]
22
+ const height = `${heights[i]}%`
23
+ return (
24
+ <Skeleton
25
+ key={i}
26
+ variant='rectangular'
27
+ sx={{
28
+ flex: 1,
29
+ height,
30
+ }}
31
+ />
32
+ )
33
+ })}
34
+ </Box>
35
+ <Box
36
+ sx={{
37
+ display: 'flex',
38
+ alignItems: 'center',
39
+ justifyContent: 'space-between',
40
+ width: '100%',
41
+ mt: ({ spacing }) => spacing(1),
42
+ }}
43
+ >
44
+ {Array(4)
45
+ .fill(0)
46
+ .map((_, i) => (
47
+ <Skeleton key={i} width={32} height={8} />
48
+ ))}
49
+ </Box>
50
+ </Box>
51
+ )
52
+ }
@@ -0,0 +1,8 @@
1
+ import type { SxProps, Theme } from '@mui/material'
2
+ import { baseSkeletonStyles } from '../_shared/skeleton'
3
+
4
+ export const styles = {
5
+ skeleton: {
6
+ graph: baseSkeletonStyles.graph,
7
+ },
8
+ } satisfies Record<string, SxProps<Theme>>
@@ -0,0 +1,17 @@
1
+ import type { EchartWidgetData, EchartWidgetState } from '../echart'
2
+ import type {
3
+ EchartWidgetOptionProps,
4
+ EchartWidgetProps,
5
+ } from '../echart/types'
6
+ import type { ConfigProps } from '../loader'
7
+
8
+ export type HistogramWidgetData = EchartWidgetData
9
+
10
+ export type HistogramWidgetState = EchartWidgetState
11
+
12
+ export type HistogramWidgetConfig = EchartWidgetProps & {
13
+ type: 'histogram'
14
+ }
15
+
16
+ export type HistogramConfig = ConfigProps &
17
+ EchartWidgetOptionProps<HistogramWidgetData>
@@ -0,0 +1,25 @@
1
+ // Widget store
2
+ export { useWidgetStore } from './stores/widget-store'
3
+ export type {
4
+ BaseWidgetState,
5
+ WidgetsStoreProps,
6
+ WidgetState,
7
+ WidgetStore,
8
+ WidgetStoreActions,
9
+ WidgetStoreState,
10
+ } from './stores/types'
11
+
12
+ // Hooks
13
+ export { useWidgetRef } from '../hooks/use-widget-ref'
14
+
15
+ // NoData
16
+ export { WidgetNoData } from './no-data'
17
+ export type { WidgetNoDataProps } from './no-data'
18
+
19
+ // Error
20
+ export { WidgetError } from './error'
21
+ export type { WidgetErrorProps } from './error'
22
+
23
+ // Note
24
+ export { WidgetNote } from './note'
25
+ export type { WidgetNoteProps } from './note'
@@ -0,0 +1,4 @@
1
+ export { WidgetLoader } from './loader'
2
+ export { mergeWidgetConfig, resolveConfig, type ConfigOrFn } from './utils'
3
+
4
+ export type { WidgetLoaderProps, ConfigProps } from './types'
@@ -0,0 +1,70 @@
1
+ import { useEffect } from 'react'
2
+ import type { WidgetLoaderProps } from './types'
3
+ import { useWidgetStore } from '../stores/widget-store'
4
+ import type { WrapperState } from '../wrapper'
5
+
6
+ export function WidgetLoader<T>(props: WidgetLoaderProps<T>) {
7
+ const setWidget = useWidgetStore((state) => state.setWidget)
8
+ const executeToolPipeline = useWidgetStore(
9
+ (state) => state.executeToolPipeline,
10
+ )
11
+
12
+ // Split into 3 effects for metadata and 1 for data pipeline:
13
+ // Each property that can be modified independently gets its own effect to avoid
14
+ // accidentally resetting other properties.
15
+ //
16
+ // - Effect 1: Type (can be modified by tools that change visualization type)
17
+ // - Effect 2: Loading/Error states (change during fetch lifecycle)
18
+ // - Effect 3: Config (can be modified by tools that change widget configuration)
19
+ // - Effect 4: Data pipeline execution (transforms data through registered tools)
20
+ // - Effect 5: Re-execute pipeline when tool state changes
21
+
22
+ // Effect 1: Type updates
23
+ useEffect(() => {
24
+ setWidget<WrapperState>(props.id, {
25
+ type: props.type,
26
+ })
27
+ }, [props.id, props.type, setWidget])
28
+
29
+ // Effect 2: Loading and error states
30
+ useEffect(() => {
31
+ setWidget<WrapperState>(props.id, {
32
+ isLoading: props.isLoading ?? false,
33
+ isFetching: props.isFetching ?? false,
34
+ error: props.error,
35
+ })
36
+ }, [props.id, props.isLoading, props.isFetching, props.error, setWidget])
37
+
38
+ // Effect 3: Config updates
39
+ useEffect(() => {
40
+ if (props.config) {
41
+ setWidget<WrapperState>(props.id, {
42
+ ...props.config,
43
+ })
44
+ }
45
+ }, [props.id, props.config, setWidget])
46
+
47
+ // Effect 4: Execute tool pipeline when props.data changes
48
+ useEffect(() => {
49
+ void executeToolPipeline(props.id, props.data)
50
+ }, [props.id, props.data, executeToolPipeline])
51
+
52
+ // Effect 5: Re-execute pipeline when tool state changes (enabled/config)
53
+ useEffect(() => {
54
+ let prevTools = useWidgetStore.getState().widgets[props.id]?.registeredTools
55
+
56
+ const unsubscribe = useWidgetStore.subscribe((state) => {
57
+ const currentTools = state.widgets[props.id]?.registeredTools
58
+
59
+ // Only re-execute if tools array changed
60
+ if (currentTools !== prevTools) {
61
+ prevTools = currentTools
62
+ void executeToolPipeline(props.id, props.data)
63
+ }
64
+ })
65
+
66
+ return unsubscribe
67
+ }, [props.id, props.data, executeToolPipeline])
68
+
69
+ return props.children
70
+ }
@@ -0,0 +1,11 @@
1
+ import type { ReactNode } from 'react'
2
+ import type { WidgetsStoreProps, WidgetState } from '../stores/types'
3
+
4
+ export interface WidgetLoaderProps<T> extends WidgetsStoreProps {
5
+ children: ReactNode
6
+ config?: T
7
+ }
8
+
9
+ export interface ConfigProps {
10
+ refUI?: WidgetState['refUI']
11
+ }
@@ -0,0 +1,112 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { resolveConfig, mergeWidgetConfig } from './utils'
3
+
4
+ describe('resolveConfig', () => {
5
+ interface TestConfig {
6
+ max: number
7
+ items: number
8
+ label?: string
9
+ }
10
+
11
+ type TestData = { value: number }[]
12
+
13
+ const baseConfig: TestConfig = {
14
+ max: 100,
15
+ items: 10,
16
+ label: 'default',
17
+ }
18
+
19
+ const testData: TestData = [{ value: 50 }, { value: 75 }]
20
+
21
+ it('should return undefined when config is undefined', () => {
22
+ const result = resolveConfig(undefined, baseConfig, testData)
23
+ expect(result).toBeUndefined()
24
+ })
25
+
26
+ it('should return the object config unchanged when config is an object', () => {
27
+ const objectConfig = { max: 200, items: 20 }
28
+ const result = resolveConfig(objectConfig, baseConfig, testData)
29
+ expect(result).toEqual(objectConfig)
30
+ })
31
+
32
+ it('should call function config with baseConfig and data when config is a function', () => {
33
+ const fnConfig = (base: TestConfig, data: TestData) => ({
34
+ max: base.max * 2,
35
+ items: data.length,
36
+ })
37
+
38
+ const result = resolveConfig(fnConfig, baseConfig, testData)
39
+ expect(result).toEqual({ max: 200, items: 2 })
40
+ })
41
+
42
+ it('should allow function config to access baseConfig properties', () => {
43
+ const fnConfig = (base: TestConfig) => ({
44
+ label: `Modified: ${base.label}`,
45
+ })
46
+
47
+ const result = resolveConfig(fnConfig, baseConfig, testData)
48
+ expect(result).toEqual({ label: 'Modified: default' })
49
+ })
50
+
51
+ it('should allow function config to compute values from data', () => {
52
+ const fnConfig = (_base: TestConfig, data: TestData) => ({
53
+ max: Math.max(...data.map((d) => d.value)),
54
+ })
55
+
56
+ const result = resolveConfig(fnConfig, baseConfig, testData)
57
+ expect(result).toEqual({ max: 75 })
58
+ })
59
+
60
+ it('should return partial config from function', () => {
61
+ const fnConfig = () => ({ items: 5 })
62
+
63
+ const result = resolveConfig(fnConfig, baseConfig, testData)
64
+ expect(result).toEqual({ items: 5 })
65
+ // Ensure it's partial - doesn't include all base properties
66
+ expect(result).not.toHaveProperty('max')
67
+ expect(result).not.toHaveProperty('label')
68
+ })
69
+ })
70
+
71
+ describe('mergeWidgetConfig', () => {
72
+ interface TestConfig {
73
+ max: number
74
+ items: number
75
+ label?: string
76
+ series?: { name: string }[]
77
+ }
78
+
79
+ it('should merge two partial configs', () => {
80
+ const base: Partial<TestConfig> = { max: 100, items: 10 }
81
+ const override: Partial<TestConfig> = { max: 200 }
82
+
83
+ const result = mergeWidgetConfig<TestConfig>(base, override)
84
+ expect(result).toEqual({ max: 200, items: 10 })
85
+ })
86
+
87
+ it('should handle undefined base config', () => {
88
+ const override: Partial<TestConfig> = { max: 200 }
89
+
90
+ const result = mergeWidgetConfig<TestConfig>(undefined, override)
91
+ expect(result).toEqual({ max: 200 })
92
+ })
93
+
94
+ it('should handle undefined override config', () => {
95
+ const base: Partial<TestConfig> = { max: 100 }
96
+
97
+ const result = mergeWidgetConfig<TestConfig>(base, undefined)
98
+ expect(result).toEqual({ max: 100 })
99
+ })
100
+
101
+ it('should replace arrays instead of merging them', () => {
102
+ const base: Partial<TestConfig> = {
103
+ series: [{ name: 'Series 1' }, { name: 'Series 2' }],
104
+ }
105
+ const override: Partial<TestConfig> = {
106
+ series: [{ name: 'New Series' }],
107
+ }
108
+
109
+ const result = mergeWidgetConfig<TestConfig>(base, override)
110
+ expect(result.series).toEqual([{ name: 'New Series' }])
111
+ })
112
+ })
@@ -0,0 +1,35 @@
1
+ import deepmerge from 'deepmerge'
2
+
3
+ /**
4
+ * Config can be either an object or a function that receives baseConfig and data
5
+ * and returns a partial config to be merged with the base.
6
+ */
7
+ export type ConfigOrFn<TConfig, TData = unknown> =
8
+ | Partial<TConfig>
9
+ | ((baseConfig: TConfig, data: TData) => Partial<TConfig>)
10
+
11
+ /**
12
+ * Resolves a config that may be either an object or a function.
13
+ * If it's a function, calls it with baseConfig and data.
14
+ * If it's an object (or undefined), returns it as-is.
15
+ */
16
+ export function resolveConfig<TConfig, TData>(
17
+ config: ConfigOrFn<TConfig, TData> | undefined,
18
+ baseConfig: TConfig,
19
+ data: TData,
20
+ ): Partial<TConfig> | undefined {
21
+ if (typeof config === 'function') {
22
+ return config(baseConfig, data)
23
+ }
24
+ return config
25
+ }
26
+
27
+ export function mergeWidgetConfig<T>(
28
+ ...options: [Partial<T> | undefined, Partial<T> | undefined]
29
+ ): T {
30
+ return deepmerge(options[0] ?? {}, options[1] ?? {}, {
31
+ arrayMerge(_, source) {
32
+ return source as T[keyof T][]
33
+ },
34
+ })
35
+ }
@@ -0,0 +1,18 @@
1
+ import { downloadToCSV, type DownloadItem } from '../actions'
2
+ import type { MarkdownWidgetConfig, MarkdownWidgetData } from './types'
3
+
4
+ export function markdownDownloadConfig(): DownloadItem<MarkdownWidgetData>[] {
5
+ return [
6
+ {
7
+ ...downloadToCSV,
8
+ modifier: async (data) => {
9
+ const content = data?.content ?? ''
10
+ return downloadToCSV.modifier([['Content'], [content]])
11
+ },
12
+ },
13
+ ]
14
+ }
15
+
16
+ export function markdownConfig(): MarkdownWidgetConfig {
17
+ return {}
18
+ }
@@ -0,0 +1,14 @@
1
+ export { Markdown } from './markdown'
2
+ export { MarkdownUI } from './markdown-ui'
3
+ export { MarkdownSkeleton } from './skeleton'
4
+ export { markdownConfig, markdownDownloadConfig } from './config'
5
+
6
+ export type {
7
+ MarkdownComponentProps,
8
+ MarkdownUIProps,
9
+ MarkdownWidgetData,
10
+ MarkdownWidgetState,
11
+ MarkdownWidgetConfig,
12
+ MarkdownDownloadConfig,
13
+ MarkdownDataItem,
14
+ } from './types'