@carto/ps-react-ui 4.6.2 → 4.7.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 (60) hide show
  1. package/dist/{download-config-C3I0jWIL.js → download-config-DNLkypdN.js} +8 -7
  2. package/dist/{download-config-C3I0jWIL.js.map → download-config-DNLkypdN.js.map} +1 -1
  3. package/dist/options-CthfUJDz.js +46 -0
  4. package/dist/options-CthfUJDz.js.map +1 -0
  5. package/dist/shared-resize-observer-98b1SK1e.js +17 -0
  6. package/dist/shared-resize-observer-98b1SK1e.js.map +1 -0
  7. package/dist/styles-BYTyKQFP.js +142 -0
  8. package/dist/{styles-Y8q7Jff3.js.map → styles-BYTyKQFP.js.map} +1 -1
  9. package/dist/types/widgets/actions/brush-toggle/brush-overlay.d.ts +24 -0
  10. package/dist/types/widgets/actions/brush-toggle/brush-toggle.d.ts +15 -10
  11. package/dist/types/widgets/actions/brush-toggle/hit-test.d.ts +19 -0
  12. package/dist/types/widgets/actions/brush-toggle/hit-test.test.d.ts +1 -0
  13. package/dist/types/widgets/actions/brush-toggle/style.d.ts +8 -0
  14. package/dist/types/widgets/actions/brush-toggle/types.d.ts +35 -1
  15. package/dist/types/widgets/utils/chart-config/index.d.ts +1 -1
  16. package/dist/types/widgets/utils/chart-config/option-builders.d.ts +27 -0
  17. package/dist/widgets/actions.js +985 -772
  18. package/dist/widgets/actions.js.map +1 -1
  19. package/dist/widgets/bar.js +34 -30
  20. package/dist/widgets/bar.js.map +1 -1
  21. package/dist/widgets/category.js +9 -8
  22. package/dist/widgets/category.js.map +1 -1
  23. package/dist/widgets/echart.js +79 -91
  24. package/dist/widgets/echart.js.map +1 -1
  25. package/dist/widgets/formula.js +43 -42
  26. package/dist/widgets/formula.js.map +1 -1
  27. package/dist/widgets/histogram.js +67 -63
  28. package/dist/widgets/histogram.js.map +1 -1
  29. package/dist/widgets/markdown.js +15 -14
  30. package/dist/widgets/markdown.js.map +1 -1
  31. package/dist/widgets/pie.js +38 -37
  32. package/dist/widgets/pie.js.map +1 -1
  33. package/dist/widgets/scatterplot.js +31 -30
  34. package/dist/widgets/scatterplot.js.map +1 -1
  35. package/dist/widgets/spread.js +47 -46
  36. package/dist/widgets/spread.js.map +1 -1
  37. package/dist/widgets/table.js +17 -16
  38. package/dist/widgets/table.js.map +1 -1
  39. package/dist/widgets/timeseries.js +35 -34
  40. package/dist/widgets/timeseries.js.map +1 -1
  41. package/dist/widgets/utils.js +2 -2
  42. package/package.json +3 -1
  43. package/src/widgets/actions/brush-toggle/brush-overlay.tsx +386 -0
  44. package/src/widgets/actions/brush-toggle/brush-toggle.tsx +88 -152
  45. package/src/widgets/actions/brush-toggle/hit-test.test.ts +65 -0
  46. package/src/widgets/actions/brush-toggle/hit-test.ts +45 -0
  47. package/src/widgets/actions/brush-toggle/style.ts +32 -0
  48. package/src/widgets/actions/brush-toggle/types.ts +36 -1
  49. package/src/widgets/bar/config.ts +5 -0
  50. package/src/widgets/echart/options.ts +1 -4
  51. package/src/widgets/histogram/config.ts +9 -4
  52. package/src/widgets/pie/config.ts +2 -0
  53. package/src/widgets/scatterplot/config.ts +2 -0
  54. package/src/widgets/timeseries/config.ts +2 -0
  55. package/src/widgets/utils/chart-config/index.ts +2 -0
  56. package/src/widgets/utils/chart-config/option-builders.test.ts +105 -1
  57. package/src/widgets/utils/chart-config/option-builders.ts +56 -0
  58. package/dist/options-D9wflre6.js +0 -49
  59. package/dist/options-D9wflre6.js.map +0 -1
  60. package/dist/styles-Y8q7Jff3.js +0 -118
@@ -0,0 +1,65 @@
1
+ import { describe, test, expect } from 'vitest'
2
+ import { hitTestCategoryRange, hitTestRects } from './hit-test'
3
+
4
+ describe('hitTestCategoryRange', () => {
5
+ test('returns empty when dataLength is zero', () => {
6
+ expect(hitTestCategoryRange(0, 5, 0)).toEqual([])
7
+ })
8
+
9
+ test('snaps fractional range outward so partial overlaps are included', () => {
10
+ // xStart=1.3, xEnd=3.7 → floor(1.3)=1, ceil(3.7)=4 → [1, 2, 3, 4]
11
+ expect(hitTestCategoryRange(1.3, 3.7, 10)).toEqual([1, 2, 3, 4])
12
+ })
13
+
14
+ test('handles integer endpoints inclusively', () => {
15
+ expect(hitTestCategoryRange(2, 4, 10)).toEqual([2, 3, 4])
16
+ })
17
+
18
+ test('clamps to [0, dataLength - 1]', () => {
19
+ expect(hitTestCategoryRange(-2.5, 12.8, 5)).toEqual([0, 1, 2, 3, 4])
20
+ })
21
+
22
+ test('normalizes reversed inputs (xEnd < xStart)', () => {
23
+ expect(hitTestCategoryRange(3.7, 1.3, 10)).toEqual([1, 2, 3, 4])
24
+ })
25
+
26
+ test('returns empty when range is entirely out of bounds', () => {
27
+ expect(hitTestCategoryRange(10, 12, 5)).toEqual([])
28
+ expect(hitTestCategoryRange(-5, -1, 5)).toEqual([])
29
+ })
30
+
31
+ test('returns adjacent indices for a very narrow fractional range when snapping outward', () => {
32
+ // xStart=2.1, xEnd=2.3 partially overlaps both categories, so floor=2 and ceil=3 → [2, 3]
33
+ expect(hitTestCategoryRange(2.1, 2.3, 10)).toEqual([2, 3])
34
+ })
35
+ })
36
+
37
+ describe('hitTestRects', () => {
38
+ test('returns empty for no rects', () => {
39
+ expect(hitTestRects([], 10)).toEqual([])
40
+ })
41
+
42
+ test('unions and dedups across overlapping rects', () => {
43
+ const rects = [
44
+ { xStart: 1, xEnd: 3 },
45
+ { xStart: 2, xEnd: 4 },
46
+ ]
47
+ expect(hitTestRects(rects, 10)).toEqual([1, 2, 3, 4])
48
+ })
49
+
50
+ test('returns sorted ascending indices for disjoint rects', () => {
51
+ const rects = [
52
+ { xStart: 7, xEnd: 8 },
53
+ { xStart: 1, xEnd: 2 },
54
+ ]
55
+ expect(hitTestRects(rects, 10)).toEqual([1, 2, 7, 8])
56
+ })
57
+
58
+ test('drops rects entirely out of bounds', () => {
59
+ const rects = [
60
+ { xStart: 20, xEnd: 25 },
61
+ { xStart: 1, xEnd: 2 },
62
+ ]
63
+ expect(hitTestRects(rects, 10)).toEqual([1, 2])
64
+ })
65
+ })
@@ -0,0 +1,45 @@
1
+ import type { BrushRect } from './types'
2
+
3
+ /**
4
+ * Returns integer dataIndices covered by a brush rectangle on a category axis.
5
+ *
6
+ * `xStart` / `xEnd` come from `instance.convertFromPixel({ xAxisIndex: 0 }, …)`
7
+ * which, for a category axis, returns fractional positions around integer
8
+ * category indices (e.g. `1.3` lands between categories 1 and 2). We snap the
9
+ * range outward (`floor` / `ceil`) so a drag that visually covers any part of
10
+ * a category's bar includes that index.
11
+ *
12
+ * Results are clamped to `[0, dataLength - 1]` and returned in ascending order.
13
+ */
14
+ export function hitTestCategoryRange(
15
+ xStart: number,
16
+ xEnd: number,
17
+ dataLength: number,
18
+ ): number[] {
19
+ if (dataLength <= 0) return []
20
+ const [lo, hi] = xStart <= xEnd ? [xStart, xEnd] : [xEnd, xStart]
21
+
22
+ const start = Math.max(0, Math.floor(lo))
23
+ const end = Math.min(dataLength - 1, Math.ceil(hi))
24
+ if (start > end) return []
25
+
26
+ const indices: number[] = []
27
+ for (let i = start; i <= end; i += 1) indices.push(i)
28
+ return indices
29
+ }
30
+
31
+ /**
32
+ * Union of `hitTestCategoryRange` across multiple rectangles. Used for
33
+ * multi-brush selections where each drawn rectangle contributes to the
34
+ * combined selection.
35
+ */
36
+ export function hitTestRects(rects: BrushRect[], dataLength: number): number[] {
37
+ if (rects.length === 0) return []
38
+ const seen = new Set<number>()
39
+ for (const rect of rects) {
40
+ for (const i of hitTestCategoryRange(rect.xStart, rect.xEnd, dataLength)) {
41
+ seen.add(i)
42
+ }
43
+ }
44
+ return Array.from(seen).sort((a, b) => a - b)
45
+ }
@@ -1,4 +1,5 @@
1
1
  import type { SxProps, Theme } from '@mui/material'
2
+ import type { CSSProperties } from 'react'
2
3
 
3
4
  export const styles = {
4
5
  container: {
@@ -12,3 +13,34 @@ export const styles = {
12
13
  },
13
14
  },
14
15
  } satisfies Record<string, SxProps<Theme>>
16
+
17
+ /**
18
+ * Plain CSS objects for the brush overlay — we're outside MUI's sx pipeline
19
+ * here because the rectangles are rendered via a React portal into the chart
20
+ * div (not part of the MUI tree). Colors borrow from the base palette; if
21
+ * theme-aware styling is needed later, move to styled components.
22
+ */
23
+ export const overlayStyles: Record<string, CSSProperties> = {
24
+ // `top` and `height` are filled in at render time from the chart's plot
25
+ // rect so rectangles don't bleed over the legend / axis labels.
26
+ //
27
+ // Colors track ECharts 6's `backgroundTint` token (used by the default
28
+ // brush) — a barely-visible pale blue-gray translucent fill that washes
29
+ // bars underneath rather than masking them. Border is a hairline dark
30
+ // alpha so the selection edges are just findable, not prominent.
31
+ rect: {
32
+ position: 'absolute',
33
+ background: 'rgba(234, 237, 245, 0.2)',
34
+ border: '1px dashed rgba(0, 0, 0, 0.15)',
35
+ pointerEvents: 'none',
36
+ },
37
+ // Live drag preview — identical to committed rect (no "in-progress" vs
38
+ // "committed" visual distinction; the preview just disappears on
39
+ // `pointerup` as the rect takes its place).
40
+ rectPreview: {
41
+ position: 'absolute',
42
+ background: 'rgba(234, 237, 245, 0.6)',
43
+ border: '1px dashed rgba(0, 0, 0, 0.15)',
44
+ pointerEvents: 'none',
45
+ },
46
+ }
@@ -14,10 +14,30 @@ export interface BrushSelectedItems {
14
14
  }
15
15
 
16
16
  /**
17
- * State stored in widget store for brush functionality
17
+ * A selection rectangle in x-axis data coords. Stored in the widget store so
18
+ * it survives config-pipeline re-renders (which call `setOption` with
19
+ * `notMerge: true` and wipe any ECharts-side state). The overlay re-projects
20
+ * these to pixel positions on every chart render / resize.
21
+ *
22
+ * Both bar and histogram widgets use `xAxis.type === 'category'`, so the
23
+ * coords are category indices (possibly fractional — `convertFromPixel`
24
+ * returns floats like `1.3` between categories 1 and 2).
25
+ */
26
+ export interface BrushRect {
27
+ xStart: number
28
+ xEnd: number
29
+ }
30
+
31
+ /**
32
+ * State stored in widget store for brush functionality.
18
33
  */
19
34
  export interface BrushConfig {
35
+ /** Whether brush mode is enabled. */
20
36
  brush?: boolean
37
+ /** Persisted selection rectangles in data-axis coords. */
38
+ brushRects?: BrushRect[]
39
+ /** Last selection emitted to the `onBrushSelected` callback. */
40
+ brushSelection?: BrushSelectedItems
21
41
  }
22
42
 
23
43
  export type BrushState<T = unknown> = BaseWidgetState<T & BrushConfig>
@@ -27,6 +47,21 @@ export interface BrushToggleProps {
27
47
  id: string
28
48
  /** Callback fired when items are selected via brush */
29
49
  onBrushSelected?: (items: BrushSelectedItems) => void
50
+ /** When true, allows multiple brush selection areas. Brush stays active after each selection. */
51
+ multiBrush?: boolean
52
+ /**
53
+ * Initial brush-enabled state. Only applied on first mount if the widget
54
+ * store has no `brush` value yet — subsequent remounts preserve whatever
55
+ * state the user has toggled to.
56
+ */
57
+ defaultEnabled?: boolean
58
+ /**
59
+ * Current selection count from the consumer (e.g. `selectedItems.length`).
60
+ * When this transitions to `0` (typically when the user presses the clear
61
+ * button in `WidgetSelectionSummary`), BrushToggle clears its persisted
62
+ * brush rectangles and the on-chart selection.
63
+ */
64
+ selections?: number
30
65
  /** Custom labels for the action */
31
66
  labels?: {
32
67
  /** Tooltip when brush is disabled (button will enable brush) */
@@ -13,6 +13,7 @@ import {
13
13
  createChartDownloadConfig,
14
14
  applyXAxisFormatter,
15
15
  niceNum,
16
+ buildSeriesLabelConfig,
16
17
  } from '../utils/chart-config'
17
18
 
18
19
  export const barDownloadConfig = createChartDownloadConfig<BarWidgetData>(
@@ -60,6 +61,9 @@ function getOption({
60
61
  axisLabel: {
61
62
  padding: [parseInt(theme.spacing(0.5)), 0, 0, 0],
62
63
  margin: 0,
64
+ showMinLabel: undefined,
65
+ showMaxLabel: undefined,
66
+ hideOverlap: true,
63
67
  },
64
68
  },
65
69
  labelFormatter,
@@ -130,6 +134,7 @@ function getOption({
130
134
  emphasis: {
131
135
  focus: 'series',
132
136
  },
137
+ ...buildSeriesLabelConfig(formatter),
133
138
  })),
134
139
  } as EchartOptionsProps
135
140
  }
@@ -23,10 +23,7 @@ export function getCommonOptions({
23
23
  },
24
24
  tooltip: {
25
25
  axisPointer: {
26
- type: 'shadow',
27
- shadowStyle: {
28
- color: 'rgba(44,48,50, 0.08)',
29
- },
26
+ type: 'line',
30
27
  },
31
28
  backgroundColor: theme.palette.grey[900],
32
29
  borderWidth: 0,
@@ -10,6 +10,7 @@ import {
10
10
  createTooltipPositioner,
11
11
  createTooltipFormatter,
12
12
  niceNum,
13
+ buildHistogramSeriesLabelConfig,
13
14
  } from '../utils/chart-config'
14
15
  import { downloadToCSV, downloadToPNG, type DownloadItem } from '../actions'
15
16
  import type { ConfigProps } from '../loader/types'
@@ -108,6 +109,7 @@ export function histogramConfig(props: HistogramConfig): HistogramWidgetConfig {
108
109
  type: 'histogram',
109
110
  option: mergeEchartWidgetConfig(getCommonOptions(props), getOption(props)),
110
111
  formatter: props.formatter,
112
+ labelFormatter: props.labelFormatter,
111
113
  }
112
114
  }
113
115
 
@@ -126,7 +128,7 @@ function getOption({
126
128
  let niceMax = 1
127
129
 
128
130
  return {
129
- legend: buildLegendConfig({ hasLegend }),
131
+ legend: buildLegendConfig({ hasLegend, labelFormatter }),
130
132
  grid: buildGridConfig(hasLegend, theme),
131
133
  xAxis: {
132
134
  type: 'category',
@@ -137,8 +139,8 @@ function getOption({
137
139
  axisLabel: {
138
140
  fontSize: theme.typography.overlineDelicate.fontSize,
139
141
  fontFamily: theme.typography.overlineDelicate.fontFamily,
140
- showMinLabel: true,
141
- showMaxLabel: true,
142
+ showMinLabel: undefined,
143
+ showMaxLabel: undefined,
142
144
  hideOverlap: true,
143
145
  margin: 0,
144
146
  padding: [
@@ -209,7 +211,9 @@ function getOption({
209
211
 
210
212
  const marker = typeof item.marker === 'string' ? item.marker : ''
211
213
  const seriesName = item.seriesName ? `${item.seriesName}: ` : ''
212
- const name = item.name ?? ''
214
+ const name = labelFormatter
215
+ ? String(labelFormatter(item.name ?? ''))
216
+ : (item.name ?? '')
213
217
 
214
218
  return { name, seriesName, marker, value: formattedValue }
215
219
  }),
@@ -222,6 +226,7 @@ function getOption({
222
226
  emphasis: {
223
227
  focus: 'series',
224
228
  },
229
+ ...buildHistogramSeriesLabelConfig(formatter),
225
230
  })),
226
231
  } as EchartOptionsProps
227
232
  }
@@ -12,6 +12,7 @@ import {
12
12
  createTooltipFormatter,
13
13
  createChartDownloadConfig,
14
14
  niceNum,
15
+ buildSeriesLabelConfig,
15
16
  } from '../utils/chart-config'
16
17
 
17
18
  export const pieDownloadConfig = createChartDownloadConfig<PieWidgetData>(
@@ -133,6 +134,7 @@ function getOption({
133
134
  emphasis: {
134
135
  focus: 'series',
135
136
  },
137
+ ...buildSeriesLabelConfig(formatter, 'x'),
136
138
  })),
137
139
  }
138
140
  }
@@ -15,6 +15,7 @@ import {
15
15
  createChartDownloadConfig,
16
16
  applyYAxisFormatter,
17
17
  applyXAxisFormatter,
18
+ buildSeriesLabelConfig,
18
19
  } from '../utils/chart-config'
19
20
 
20
21
  export const scatterplotDownloadConfig =
@@ -129,6 +130,7 @@ function getOption({
129
130
  datasetIndex: index,
130
131
  type: 'scatter',
131
132
  symbolSize: 8,
133
+ ...buildSeriesLabelConfig(formatter),
132
134
  })),
133
135
  } as EchartOptionsProps
134
136
  }
@@ -16,6 +16,7 @@ import {
16
16
  createChartDownloadConfig,
17
17
  applyYAxisFormatter,
18
18
  applyXAxisFormatter,
19
+ buildSeriesLabelConfig,
19
20
  } from '../utils/chart-config'
20
21
 
21
22
  export const timeseriesDownloadConfig =
@@ -129,6 +130,7 @@ function getOption({
129
130
  emphasis: {
130
131
  focus: 'series',
131
132
  },
133
+ ...buildSeriesLabelConfig(formatter),
132
134
  })),
133
135
  } as EchartOptionsProps
134
136
  }
@@ -21,6 +21,8 @@ export {
21
21
  applyXAxisFormatter,
22
22
  applyYAxisFormatter,
23
23
  niceNum,
24
+ buildSeriesLabelConfig,
25
+ buildHistogramSeriesLabelConfig,
24
26
  } from './option-builders'
25
27
 
26
28
  export { createChartDownloadConfig } from './download-config'
@@ -1,5 +1,10 @@
1
1
  import { describe, it, expect } from 'vitest'
2
- import { niceNum } from './option-builders'
2
+ import type { CallbackDataParams } from 'echarts/types/dist/shared'
3
+ import {
4
+ niceNum,
5
+ buildSeriesLabelConfig,
6
+ buildHistogramSeriesLabelConfig,
7
+ } from './option-builders'
3
8
 
4
9
  describe('niceNum', () => {
5
10
  it('should return 0 for 0', () => {
@@ -38,3 +43,102 @@ describe('niceNum', () => {
38
43
  expect(niceNum(1)).toBe(1)
39
44
  })
40
45
  })
46
+
47
+ describe('buildSeriesLabelConfig', () => {
48
+ it('should return empty object when no formatter provided', () => {
49
+ expect(buildSeriesLabelConfig()).toEqual({})
50
+ expect(buildSeriesLabelConfig(undefined)).toEqual({})
51
+ })
52
+
53
+ it('should return label config with formatter when formatter provided', () => {
54
+ const formatter = (v: number) => `$${v}`
55
+ const result = buildSeriesLabelConfig(formatter)
56
+ expect(result).toHaveProperty('label')
57
+ expect((result as { label: { formatter: unknown } }).label).toHaveProperty(
58
+ 'formatter',
59
+ )
60
+ })
61
+
62
+ it('should format value from dataset params using y encode key', () => {
63
+ const formatter = (v: number) => `$${v}`
64
+ const result = buildSeriesLabelConfig(formatter, 'y')
65
+ const label = (
66
+ result as {
67
+ label: { formatter: (p: Partial<CallbackDataParams>) => string }
68
+ }
69
+ ).label
70
+ const params = {
71
+ encode: { y: [1] },
72
+ dimensionNames: ['category', 'amount'],
73
+ value: { category: 'A', amount: 42 },
74
+ }
75
+ expect(label.formatter(params as unknown as CallbackDataParams)).toBe('$42')
76
+ })
77
+
78
+ it('should format value from dataset params using x encode key', () => {
79
+ const formatter = (v: number) => `${v}%`
80
+ const result = buildSeriesLabelConfig(formatter, 'x')
81
+ const label = (
82
+ result as {
83
+ label: { formatter: (p: Partial<CallbackDataParams>) => string }
84
+ }
85
+ ).label
86
+ const params = {
87
+ encode: { x: [1] },
88
+ dimensionNames: ['name', 'value'],
89
+ value: { name: 'Foo', value: 75 },
90
+ }
91
+ expect(label.formatter(params as unknown as CallbackDataParams)).toBe('75%')
92
+ })
93
+
94
+ it('should return empty string when encode index is undefined', () => {
95
+ const formatter = (v: number) => `$${v}`
96
+ const result = buildSeriesLabelConfig(formatter, 'y')
97
+ const label = (
98
+ result as {
99
+ label: { formatter: (p: Partial<CallbackDataParams>) => string }
100
+ }
101
+ ).label
102
+ const params = {
103
+ encode: {},
104
+ dimensionNames: ['category', 'amount'],
105
+ value: { category: 'A', amount: 42 },
106
+ }
107
+ expect(label.formatter(params as unknown as CallbackDataParams)).toBe('')
108
+ })
109
+ })
110
+
111
+ describe('buildHistogramSeriesLabelConfig', () => {
112
+ it('should return empty object when no formatter provided', () => {
113
+ expect(buildHistogramSeriesLabelConfig()).toEqual({})
114
+ expect(buildHistogramSeriesLabelConfig(undefined)).toEqual({})
115
+ })
116
+
117
+ it('should format raw numeric value', () => {
118
+ const formatter = (v: number) => `${v} units`
119
+ const result = buildHistogramSeriesLabelConfig(formatter)
120
+ const label = (
121
+ result as {
122
+ label: { formatter: (p: Partial<CallbackDataParams>) => string }
123
+ }
124
+ ).label
125
+ const params = { value: 100 }
126
+ expect(label.formatter(params as unknown as CallbackDataParams)).toBe(
127
+ '100 units',
128
+ )
129
+ })
130
+
131
+ it('should stringify non-numeric values', () => {
132
+ const formatter = (v: number) => `${v} units`
133
+ const result = buildHistogramSeriesLabelConfig(formatter)
134
+ const label = (
135
+ result as {
136
+ label: { formatter: (p: Partial<CallbackDataParams>) => string }
137
+ }
138
+ ).label
139
+ const params = { value: 'text' }
140
+ expect(label.formatter(params as unknown as CallbackDataParams)).toBe(
141
+ 'text',
142
+ )
143
+ })
144
+ })
@@ -225,3 +225,59 @@ export function createTooltipFormatter(
225
225
  return tooltip(name, formattedValues.join(''))
226
226
  }
227
227
  }
228
+
229
+ /**
230
+ * Builds a series `label` config that applies formatter to the data value
231
+ * extracted from a dataset row using ECharts encode/dimensionNames.
232
+ *
233
+ * Does not set `show` — labels remain hidden by default per ECharts defaults.
234
+ *
235
+ * @param formatter - Optional numeric value formatter
236
+ * @param encodeKey - The encode dimension key to extract ('y' for vertical charts, 'x' for horizontal)
237
+ */
238
+ export function buildSeriesLabelConfig(
239
+ formatter?: (value: number) => string,
240
+ encodeKey = 'y',
241
+ ): { label: { formatter: (params: CallbackDataParams) => string } } | object {
242
+ if (!formatter) return {}
243
+
244
+ return {
245
+ label: {
246
+ formatter: (params: CallbackDataParams) => {
247
+ const encodeIndex = params.encode?.[encodeKey]?.[0]
248
+ if (encodeIndex === undefined) return ''
249
+ const dimName = params.dimensionNames?.[encodeIndex]
250
+ const row = params.value as Record<string, string | number>
251
+ const value = dimName ? row[dimName] : undefined
252
+ return typeof value === 'number'
253
+ ? formatter(value)
254
+ : String(value ?? '')
255
+ },
256
+ },
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Builds a series `label` config that applies formatter to a raw numeric value.
262
+ * Used by histogram where series data is number[] (not datasets).
263
+ *
264
+ * Does not set `show` — labels remain hidden by default per ECharts defaults.
265
+ *
266
+ * @param formatter - Optional numeric value formatter
267
+ */
268
+ export function buildHistogramSeriesLabelConfig(
269
+ formatter?: (value: number) => string,
270
+ ): { label: { formatter: (params: CallbackDataParams) => string } } | object {
271
+ if (!formatter) return {}
272
+
273
+ return {
274
+ label: {
275
+ formatter: (params: CallbackDataParams) => {
276
+ const value = params.value as number
277
+ return typeof value === 'number'
278
+ ? formatter(value)
279
+ : String(value ?? '')
280
+ },
281
+ },
282
+ }
283
+ }
@@ -1,49 +0,0 @@
1
- function t({
2
- theme: o
3
- }) {
4
- return {
5
- grid: {
6
- left: parseInt(o.spacing(1)),
7
- top: parseInt(o.spacing(3)),
8
- right: parseInt(o.spacing(1)),
9
- bottom: parseInt(o.spacing(4)),
10
- containLabel: !0
11
- },
12
- toolbox: {
13
- show: !1
14
- },
15
- tooltip: {
16
- axisPointer: {
17
- type: "shadow",
18
- shadowStyle: {
19
- color: "rgba(44,48,50, 0.08)"
20
- }
21
- },
22
- backgroundColor: o.palette.grey[900],
23
- borderWidth: 0,
24
- padding: [parseInt(o.spacing(1)), parseInt(o.spacing(1))],
25
- textStyle: {
26
- color: o.palette.common.white,
27
- fontSize: 11,
28
- fontFamily: o.typography.caption.fontFamily
29
- },
30
- trigger: "axis"
31
- },
32
- legend: {
33
- type: "scroll",
34
- bottom: 0
35
- },
36
- axisPointer: {
37
- lineStyle: {
38
- color: o.palette.grey[400]
39
- }
40
- },
41
- xAxis: {},
42
- yAxis: {},
43
- color: [o.palette.secondary.main, ...Object.values(o.palette.qualitative?.bold ?? {})]
44
- };
45
- }
46
- export {
47
- t as g
48
- };
49
- //# sourceMappingURL=options-D9wflre6.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"options-D9wflre6.js","sources":["../src/widgets/echart/options.ts"],"sourcesContent":["import type { EchartOptionsProps, EchartWidgetOptionProps } from './types'\n\n/**\n * Returns the shared base ECharts options used across all EChart-based widgets (bar, pie, histogram, etc.).\n *\n * @remarks\n * Configures grid spacing, tooltip styling, legend, axis pointer, and the default color palette\n * derived from the MUI theme.\n */\nexport function getCommonOptions({\n theme,\n}: EchartWidgetOptionProps<unknown>): EchartOptionsProps {\n return {\n grid: {\n left: parseInt(theme.spacing(1)),\n top: parseInt(theme.spacing(3)),\n right: parseInt(theme.spacing(1)),\n bottom: parseInt(theme.spacing(4)),\n containLabel: true,\n },\n toolbox: {\n show: false,\n },\n tooltip: {\n axisPointer: {\n type: 'shadow',\n shadowStyle: {\n color: 'rgba(44,48,50, 0.08)',\n },\n },\n backgroundColor: theme.palette.grey[900],\n borderWidth: 0,\n padding: [parseInt(theme.spacing(1)), parseInt(theme.spacing(1))],\n textStyle: {\n color: theme.palette.common.white,\n fontSize: 11,\n fontFamily: theme.typography.caption.fontFamily,\n },\n trigger: 'axis',\n },\n legend: {\n type: 'scroll',\n bottom: 0,\n },\n axisPointer: {\n lineStyle: {\n color: theme.palette.grey[400],\n },\n },\n xAxis: {},\n yAxis: {},\n color: [\n theme.palette.secondary.main,\n ...Object.values(\n (theme.palette as { qualitative?: { bold?: Record<string, string> } })\n .qualitative?.bold ?? {},\n ),\n ],\n }\n}\n"],"names":["getCommonOptions","theme","grid","left","parseInt","spacing","top","right","bottom","containLabel","toolbox","show","tooltip","axisPointer","type","shadowStyle","color","backgroundColor","palette","grey","borderWidth","padding","textStyle","common","white","fontSize","fontFamily","typography","caption","trigger","legend","lineStyle","xAxis","yAxis","secondary","main","Object","values","qualitative","bold"],"mappings":"AASO,SAASA,EAAiB;AAAA,EAC/BC,OAAAA;AACgC,GAAuB;AACvD,SAAO;AAAA,IACLC,MAAM;AAAA,MACJC,MAAMC,SAASH,EAAMI,QAAQ,CAAC,CAAC;AAAA,MAC/BC,KAAKF,SAASH,EAAMI,QAAQ,CAAC,CAAC;AAAA,MAC9BE,OAAOH,SAASH,EAAMI,QAAQ,CAAC,CAAC;AAAA,MAChCG,QAAQJ,SAASH,EAAMI,QAAQ,CAAC,CAAC;AAAA,MACjCI,cAAc;AAAA,IAAA;AAAA,IAEhBC,SAAS;AAAA,MACPC,MAAM;AAAA,IAAA;AAAA,IAERC,SAAS;AAAA,MACPC,aAAa;AAAA,QACXC,MAAM;AAAA,QACNC,aAAa;AAAA,UACXC,OAAO;AAAA,QAAA;AAAA,MACT;AAAA,MAEFC,iBAAiBhB,EAAMiB,QAAQC,KAAK,GAAG;AAAA,MACvCC,aAAa;AAAA,MACbC,SAAS,CAACjB,SAASH,EAAMI,QAAQ,CAAC,CAAC,GAAGD,SAASH,EAAMI,QAAQ,CAAC,CAAC,CAAC;AAAA,MAChEiB,WAAW;AAAA,QACTN,OAAOf,EAAMiB,QAAQK,OAAOC;AAAAA,QAC5BC,UAAU;AAAA,QACVC,YAAYzB,EAAM0B,WAAWC,QAAQF;AAAAA,MAAAA;AAAAA,MAEvCG,SAAS;AAAA,IAAA;AAAA,IAEXC,QAAQ;AAAA,MACNhB,MAAM;AAAA,MACNN,QAAQ;AAAA,IAAA;AAAA,IAEVK,aAAa;AAAA,MACXkB,WAAW;AAAA,QACTf,OAAOf,EAAMiB,QAAQC,KAAK,GAAG;AAAA,MAAA;AAAA,IAC/B;AAAA,IAEFa,OAAO,CAAA;AAAA,IACPC,OAAO,CAAA;AAAA,IACPjB,OAAO,CACLf,EAAMiB,QAAQgB,UAAUC,MACxB,GAAGC,OAAOC,OACPpC,EAAMiB,QACJoB,aAAaC,QAAQ,CAAA,CAC1B,CAAC;AAAA,EAAA;AAGP;"}