@carto/ps-react-ui 6.2.0 → 6.3.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 (68) hide show
  1. package/dist/{actions-CueYrfVr.js → actions-CkxKe8-J.js} +56 -46
  2. package/dist/actions-CkxKe8-J.js.map +1 -0
  3. package/dist/{option-builders-DQivvvbb.js → item-color-B7xkIpDZ.js} +26 -9
  4. package/dist/item-color-B7xkIpDZ.js.map +1 -0
  5. package/dist/types/widgets/bar/types.d.ts +6 -0
  6. package/dist/types/widgets/histogram/bins.d.ts +7 -0
  7. package/dist/types/widgets/histogram/download.d.ts +2 -2
  8. package/dist/types/widgets/histogram/index.d.ts +2 -1
  9. package/dist/types/widgets/histogram/options.d.ts +1 -1
  10. package/dist/types/widgets/histogram/transforms.d.ts +5 -4
  11. package/dist/types/widgets/histogram/types.d.ts +22 -5
  12. package/dist/types/widgets/index.d.ts +1 -1
  13. package/dist/types/widgets/pie/types.d.ts +6 -0
  14. package/dist/types/widgets/scatterplot/download.d.ts +2 -2
  15. package/dist/types/widgets/scatterplot/index.d.ts +2 -1
  16. package/dist/types/widgets/scatterplot/points.d.ts +7 -0
  17. package/dist/types/widgets/scatterplot/transforms.d.ts +4 -3
  18. package/dist/types/widgets/scatterplot/types.d.ts +21 -2
  19. package/dist/types/widgets/timeseries/types.d.ts +6 -0
  20. package/dist/types/widgets/utils/item-color.d.ts +26 -0
  21. package/dist/widgets/actions.js +1 -1
  22. package/dist/widgets/bar.js +78 -70
  23. package/dist/widgets/bar.js.map +1 -1
  24. package/dist/widgets/histogram.js +116 -85
  25. package/dist/widgets/histogram.js.map +1 -1
  26. package/dist/widgets/pie.js +108 -89
  27. package/dist/widgets/pie.js.map +1 -1
  28. package/dist/widgets/scatterplot.js +131 -92
  29. package/dist/widgets/scatterplot.js.map +1 -1
  30. package/dist/widgets/timeseries.js +82 -74
  31. package/dist/widgets/timeseries.js.map +1 -1
  32. package/dist/widgets.js +1 -1
  33. package/dist/widgets.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/widgets/actions/fullscreen/fullscreen-store.test.tsx +77 -13
  36. package/src/widgets/actions/fullscreen/fullscreen.tsx +48 -5
  37. package/src/widgets/bar/options.test.ts +106 -0
  38. package/src/widgets/bar/options.ts +25 -14
  39. package/src/widgets/bar/types.ts +6 -0
  40. package/src/widgets/histogram/bins.ts +22 -0
  41. package/src/widgets/histogram/download.test.ts +10 -0
  42. package/src/widgets/histogram/download.ts +7 -3
  43. package/src/widgets/histogram/index.ts +3 -0
  44. package/src/widgets/histogram/options.test.ts +62 -0
  45. package/src/widgets/histogram/options.ts +38 -17
  46. package/src/widgets/histogram/transforms.test.ts +21 -7
  47. package/src/widgets/histogram/transforms.ts +26 -12
  48. package/src/widgets/histogram/types.ts +25 -5
  49. package/src/widgets/index.ts +6 -1
  50. package/src/widgets/pie/options.test.ts +91 -0
  51. package/src/widgets/pie/options.ts +50 -20
  52. package/src/widgets/pie/types.ts +6 -0
  53. package/src/widgets/scatterplot/download.test.ts +9 -0
  54. package/src/widgets/scatterplot/download.ts +5 -3
  55. package/src/widgets/scatterplot/index.ts +3 -0
  56. package/src/widgets/scatterplot/options.test.ts +78 -0
  57. package/src/widgets/scatterplot/options.ts +35 -11
  58. package/src/widgets/scatterplot/points.ts +35 -0
  59. package/src/widgets/scatterplot/transforms.test.ts +19 -0
  60. package/src/widgets/scatterplot/transforms.ts +23 -18
  61. package/src/widgets/scatterplot/types.ts +25 -2
  62. package/src/widgets/timeseries/options.test.ts +65 -0
  63. package/src/widgets/timeseries/options.ts +31 -14
  64. package/src/widgets/timeseries/types.ts +6 -0
  65. package/src/widgets/utils/item-color.test.ts +74 -0
  66. package/src/widgets/utils/item-color.ts +55 -0
  67. package/dist/actions-CueYrfVr.js.map +0 -1
  68. package/dist/option-builders-DQivvvbb.js.map +0 -1
@@ -2,12 +2,29 @@ import { Theme } from '@mui/material';
2
2
  import { EChartsOption } from 'echarts';
3
3
  import { WidgetSeries } from '../types.js';
4
4
  /**
5
- * Histogram widget data — array of series, each a flat array of bin counts.
6
- * The option factory's merge phase (see {@link createHistogramOptionFactory})
7
- * combines this with `ticks` to produce a 2-column dataset (`[binLabel, count]`)
8
- * for ECharts.
5
+ * One histogram bin: either its count, or `{ value, color? }` to give the
6
+ * bar its own colour (CSS colour or theme palette path such as
7
+ * `'primary.main'`). A bin `color` wins over the template's
8
+ * `itemStyle.color` and the series colour; selection dimming still applies.
9
9
  */
10
- export type HistogramWidgetData = readonly (readonly number[])[];
10
+ export type HistogramBin = number | HistogramBinObject;
11
+ /** Object form of a {@link HistogramBin}. */
12
+ export interface HistogramBinObject {
13
+ value: number;
14
+ color?: string;
15
+ }
16
+ /**
17
+ * Histogram widget data — array of series, each a flat array of bins. The
18
+ * option factory's merge phase (see {@link createHistogramOptionFactory})
19
+ * combines this with `ticks` to produce a 2-column dataset
20
+ * (`[binLabel, count]`) for ECharts.
21
+ *
22
+ * Defaults to plain counts (`number[][]`) so existing code that reads bins
23
+ * as numbers keeps type-checking; use `HistogramWidgetData<HistogramBin>`
24
+ * to also accept `{ value, color? }` bins. Every histogram API (option
25
+ * factory, transforms, download) accepts both forms.
26
+ */
27
+ export type HistogramWidgetData<B extends HistogramBin = number> = readonly (readonly B[])[];
11
28
  /** Inputs to the structural-only {@link histogramOptions} builder. */
12
29
  export interface HistogramOptionsInput {
13
30
  theme: Theme;
@@ -101,7 +101,7 @@ export type { FormulaUIProps, FormulaDataItem, FormulaWidgetData, } from './form
101
101
  export type { MarkdownUIProps, MarkdownWidgetData } from './markdown/index.js';
102
102
  export type { PieDatum, PieWidgetData } from './pie/index.js';
103
103
  export type { TimeseriesDatum, TimeseriesWidgetData } from './timeseries/index.js';
104
- export type { ScatterplotDatum, ScatterplotWidgetData } from './scatterplot/index.js';
104
+ export type { ScatterplotDatum, ScatterplotPoint, ScatterplotItem, ScatterplotWidgetData, } from './scatterplot/index.js';
105
105
  export type { SpreadUIProps, SpreadDataItem, SpreadWidgetData, SpreadVariant, } from './spread/index.js';
106
106
  export type { RangeProps, RangeUIProps, RangeDataItem, RangeWidgetData, RangeItemValue, } from './range/index.js';
107
107
  export type { CategoryProps, CategoryUIProps, CategoryDataItem, CategoryWidgetData, CategoryKey, CategorySeriesConfig, CategoryLabels, } from './category/index.js';
@@ -5,6 +5,12 @@ import { WidgetSeries } from '../types.js';
5
5
  export interface PieDatum {
6
6
  name: string | number;
7
7
  value: number;
8
+ /**
9
+ * Optional colour for this item (CSS colour or theme palette path such as
10
+ * `'primary.main'`). Wins over the template's `itemStyle.color` and the
11
+ * series colour; selection dimming still applies on top.
12
+ */
13
+ color?: string;
8
14
  }
9
15
  /** Pie widget data — one slice array per series (rendered as side-by-side donuts). */
10
16
  export type PieWidgetData = readonly (readonly PieDatum[])[];
@@ -1,11 +1,11 @@
1
1
  import { DownloadItem, WidgetDownloadArgs } from '../actions/download/index.js';
2
- import { ScatterplotWidgetData } from './types.js';
2
+ import { ScatterplotItem, ScatterplotWidgetData } from './types.js';
3
3
  /**
4
4
  * Download menu items for the Scatterplot widget. Always includes a CSV item
5
5
  * with `series, x, y` columns (one row per point). When `getCaptureEl` is
6
6
  * given, prepends a PNG item that rasterises the captured element via
7
7
  * `html2canvas`.
8
8
  */
9
- export declare function createScatterplotDownloadConfig(args: WidgetDownloadArgs<ScatterplotWidgetData> & {
9
+ export declare function createScatterplotDownloadConfig(args: WidgetDownloadArgs<ScatterplotWidgetData<ScatterplotItem>> & {
10
10
  seriesNames?: readonly string[];
11
11
  }): DownloadItem[];
@@ -2,4 +2,5 @@ export { scatterplotOptions, createScatterplotOptionFactory } from './options.js
2
2
  export { ScatterplotSkeleton, type ScatterplotSkeletonProps } from './skeleton.js';
3
3
  export { createScatterplotDownloadConfig } from './download.js';
4
4
  export { toRelativeScatterplotData, filterScatterplotByLockedPoints, } from './transforms.js';
5
- export type { ScatterplotDatum, ScatterplotWidgetData, ScatterplotOptionsInput, ScatterplotOptionFactoryInput, ScatterplotEChartsOption, } from './types.js';
5
+ export { getScatterplotXY } from './points.js';
6
+ export type { ScatterplotDatum, ScatterplotPoint, ScatterplotItem, ScatterplotWidgetData, ScatterplotOptionsInput, ScatterplotOptionFactoryInput, ScatterplotEChartsOption, } from './types.js';
@@ -0,0 +1,7 @@
1
+ import { ScatterplotItem } from './types.js';
2
+ /** `[x, y]` of a {@link ScatterplotItem}, whichever form it takes. */
3
+ export declare function getScatterplotXY(point: ScatterplotItem): readonly [number, number];
4
+ /** Whether `v` is a valid {@link ScatterplotItem} with finite coordinates. */
5
+ export declare function isScatterplotDatum(v: unknown): v is ScatterplotItem;
6
+ /** Same point with new coordinates; keeps the object form (and `color`). */
7
+ export declare function withScatterplotXY(point: ScatterplotItem, x: number, y: number): ScatterplotItem;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Scatterplot-specific `RelativeData` transform. Scatter data is
3
- * `[number, number][]` — each series is a list of `[x, y]` tuples.
3
+ * `ScatterplotItem[][]` — each series is a list of `[x, y]` tuples or
4
+ * `{ x, y, color? }` points (whose shape is kept).
4
5
  * Relative is a values-axis concept, so this rewrites `y` to its
5
6
  * share of the series's total `y` (0–100) and leaves `x` raw — x is
6
7
  * coordinate space, not part of the cohort total.
@@ -11,12 +12,12 @@
11
12
  * y values produce sane signed shares-of-magnitude. A series whose
12
13
  * total y-magnitude is zero (all-zero or empty input) is returned
13
14
  * unchanged so a stalled or empty data set doesn't show misleading 0%
14
- * values. Inputs whose shape isn't `[number, number][]` fall through
15
+ * values. Inputs whose shape isn't `ScatterplotItem[]` fall through
15
16
  * untouched.
16
17
  */
17
18
  export declare const toRelativeScatterplotData: (input: unknown) => unknown;
18
19
  /**
19
- * `LockSelection` filter for Scatterplot. Data is `[number, number][][]` —
20
+ * `LockSelection` filter for Scatterplot. Data is `ScatterplotItem[][]` —
20
21
  * points have no `name`, so selection (and locking) is keyed on a synthetic
21
22
  * `${seriesIndex}:${dataIndex}` string (same format `useChartSelection`'s
22
23
  * `keyFromClick`/`keysFromBrush` produce for this widget). Unlike Histogram,
@@ -3,8 +3,27 @@ import { EChartsOption } from 'echarts';
3
3
  import { WidgetSeries } from '../types.js';
4
4
  /** A single point — `[x, y]` tuple. */
5
5
  export type ScatterplotDatum = readonly [number, number];
6
- /** Scatterplot widget data — array of series, each a list of `[x, y]` tuples. */
7
- export type ScatterplotWidgetData = readonly (readonly ScatterplotDatum[])[];
6
+ /**
7
+ * Object form of a point, to give it its own colour. `color` (CSS colour or
8
+ * theme palette path such as `'primary.main'`) wins over the template's
9
+ * `itemStyle.color` and the series colour; selection dimming still applies.
10
+ */
11
+ export interface ScatterplotPoint {
12
+ x: number;
13
+ y: number;
14
+ color?: string;
15
+ }
16
+ /** Any accepted point: an `[x, y]` tuple or a {@link ScatterplotPoint}. */
17
+ export type ScatterplotItem = ScatterplotDatum | ScatterplotPoint;
18
+ /**
19
+ * Scatterplot widget data — array of series, each a list of points.
20
+ *
21
+ * Defaults to `[x, y]` tuples so existing code that destructures points
22
+ * keeps type-checking; use `ScatterplotWidgetData<ScatterplotItem>` to also
23
+ * accept `{ x, y, color? }` points. Every scatterplot API (option factory,
24
+ * transforms, download) accepts both forms.
25
+ */
26
+ export type ScatterplotWidgetData<P extends ScatterplotItem = ScatterplotDatum> = readonly (readonly P[])[];
8
27
  /** Inputs to the structural-only {@link scatterplotOptions} builder. */
9
28
  export interface ScatterplotOptionsInput {
10
29
  theme: Theme;
@@ -9,6 +9,12 @@ import { WidgetSeries } from '../types.js';
9
9
  export interface TimeseriesDatum {
10
10
  name: Date | number | string;
11
11
  value: number;
12
+ /**
13
+ * Optional colour for this item (CSS colour or theme palette path such as
14
+ * `'primary.main'`). Wins over the template's `itemStyle.color` and the
15
+ * series colour; selection dimming still applies on top.
16
+ */
17
+ color?: string;
12
18
  }
13
19
  /** Timeseries widget data — one array of points per series. */
14
20
  export type TimeseriesWidgetData = readonly (readonly TimeseriesDatum[])[];
@@ -0,0 +1,26 @@
1
+ import { Theme } from '@mui/material';
2
+ import { CallbackDataParams } from 'echarts/types/dist/shared';
3
+ /** ECharts `itemStyle.color` callback, as emitted by the chart widgets. */
4
+ export type ItemColorCallback = (params: CallbackDataParams) => string;
5
+ /**
6
+ * Builds the callback that resolves the **base** colour of every item of one
7
+ * series, before any selection dimming. Priority:
8
+ *
9
+ * 1. the datum's own `color` (`datums[params.dataIndex].color`);
10
+ * 2. the consumer's `template.itemStyle.color` (from `optionsOverride`):
11
+ * a string is used as is, a function is called with the ECharts params;
12
+ * 3. `fallback` — the widget's default (series colour / palette).
13
+ *
14
+ * The datum is looked up by `params.dataIndex` in the widget's own data
15
+ * rather than read off `params.data`, so it works whatever the dataset row
16
+ * shape is (object rows, `[label, count]` tuples, `[x, y]` tuples).
17
+ *
18
+ * Datum and template colours go through {@link resolveThemeColor}, same as
19
+ * per-series colours, so palette paths such as `'primary.main'` work.
20
+ */
21
+ export declare function createItemColorResolver({ theme, datums, template, fallback, }: {
22
+ theme: Theme;
23
+ datums: readonly unknown[];
24
+ template: unknown;
25
+ fallback: ItemColorCallback;
26
+ }): ItemColorCallback;
@@ -1,4 +1,4 @@
1
- import { C as e, E as t, S as n, T as r, _ as i, a, b as o, c as s, d as c, f as l, g as u, h as d, i as f, l as p, m, n as h, o as g, p as _, r as v, s as y, t as b, u as x, v as S, w as C, x as w, y as T } from "../actions-CueYrfVr.js";
1
+ import { C as e, E as t, S as n, T as r, _ as i, a, b as o, c as s, d as c, f as l, g as u, h as d, i as f, l as p, m, n as h, o as g, p as _, r as v, s as y, t as b, u as x, v as S, w as C, x as w, y as T } from "../actions-CkxKe8-J.js";
2
2
  import { a as E, i as D, n as O, r as k, t as A } from "../zoom-toggle-MmLjMTEw.js";
3
3
  import { a as j, c as M, d as N, f as P, i as F, l as I, n as L, o as R, p as z, r as B, s as V, t as H, u as U } from "../download-B4sykOFm.js";
4
4
  export { l as BrushToggle, j as CSVIcon, b as ChangeColumn, _ as DEFAULT_BRUSH_TOGGLE_LABELS, h as DEFAULT_CHANGE_COLUMN_LABELS, I as DEFAULT_DOWNLOAD_LABELS, y as DEFAULT_FULLSCREEN_LABELS, f as DEFAULT_LOCK_SELECTION_LABELS, p as DEFAULT_RELATIVE_DATA_LABELS, r as DEFAULT_SEARCHER_LABELS, S as DEFAULT_SHOW_ALL_LABELS, o as DEFAULT_STACK_TOGGLE_LABELS, O as DEFAULT_ZOOM_TOGGLE_LABELS, F as DOWNLOAD_ITEM_IDS, M as Download, g as FullScreen, v as LockSelection, R as MarkdownIcon, V as PNGIcon, s as RelativeData, d as SHOW_ALL_ID, n as Searcher, e as SearcherToggle, u as ShowAllToggle, T as StackToggle, k as ZOOM_LAYOUT, A as ZoomToggle, m as addBrush, w as addStack, D as addZoom, L as buildCsvDownloadItem, B as buildPngDownloadItem, E as createAddZoom, x as createPercentFormatter, U as downloadDOMToPNG, N as downloadToCSV, a as filterByLockedItems, t as filterBySearchText, C as setSearcherText, i as setShowAll, P as toCsvString, c as toRelativeData, z as triggerLinkDownload, H as withPngItem };
@@ -1,20 +1,20 @@
1
1
  import { r as e } from "../zoom-toggle-MmLjMTEw.js";
2
2
  import { n as t, t as n } from "../download-B4sykOFm.js";
3
3
  import { n as r, r as i, t as a } from "../utils-C-eWwOhE.js";
4
- import { a as o, n as s, o as c, r as l, s as u, t as d } from "../option-builders-DQivvvbb.js";
5
- import { c as f } from "react/compiler-runtime";
6
- import { Box as p, Skeleton as m } from "@mui/material";
7
- import { jsx as h, jsxs as g } from "react/jsx-runtime";
8
- import * as _ from "echarts";
4
+ import { c as o, i as s, n as c, o as l, r as u, s as d, t as f } from "../item-color-B7xkIpDZ.js";
5
+ import { c as p } from "react/compiler-runtime";
6
+ import { Box as m, Skeleton as h } from "@mui/material";
7
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
8
+ import * as v from "echarts";
9
9
  //#region src/widgets/bar/options.ts
10
- function v({ theme: e, formatter: t, labelFormatter: n }) {
10
+ function y({ theme: e, formatter: t, labelFormatter: n }) {
11
11
  let r = 0, i = 1;
12
12
  return {
13
13
  grid: {
14
14
  left: parseInt(e.spacing(1)),
15
15
  top: parseInt(e.spacing(3)),
16
16
  right: parseInt(e.spacing(1)),
17
- ...s(!1, e),
17
+ ...u(!1, e),
18
18
  containLabel: !0
19
19
  },
20
20
  tooltip: {
@@ -28,10 +28,10 @@ function v({ theme: e, formatter: t, labelFormatter: n }) {
28
28
  fontFamily: e.typography.caption.fontFamily
29
29
  },
30
30
  axisPointer: { type: "line" },
31
- position: c(e),
32
- formatter: b(t, n)
31
+ position: d(e),
32
+ formatter: x(t, n)
33
33
  },
34
- legend: { ...l({
34
+ legend: { ...s({
35
35
  hasLegend: !1,
36
36
  labelFormatter: n
37
37
  }) },
@@ -42,7 +42,7 @@ function v({ theme: e, formatter: t, labelFormatter: n }) {
42
42
  axisLine: { show: !1 },
43
43
  axisTick: { show: !1 },
44
44
  axisLabel: {
45
- ...d(e),
45
+ ...c(e),
46
46
  padding: [
47
47
  parseInt(e.spacing(.5)),
48
48
  0,
@@ -57,8 +57,8 @@ function v({ theme: e, formatter: t, labelFormatter: n }) {
57
57
  },
58
58
  yAxis: {
59
59
  type: "value",
60
- min: (e) => (r = e.min < 0 ? u(e.min) : 0, r),
61
- max: (e) => (i = e.max <= 0 ? 1 : u(e.max), i),
60
+ min: (e) => (r = e.min < 0 ? o(e.min) : 0, r),
61
+ max: (e) => (i = e.max <= 0 ? 1 : o(e.max), i),
62
62
  axisLine: { show: !1 },
63
63
  axisTick: { show: !1 },
64
64
  splitLine: {
@@ -66,7 +66,7 @@ function v({ theme: e, formatter: t, labelFormatter: n }) {
66
66
  lineStyle: { color: e.palette.black?.[4] ?? e.palette.divider }
67
67
  },
68
68
  axisLabel: {
69
- ...d(e),
69
+ ...c(e),
70
70
  margin: parseInt(e.spacing(1)),
71
71
  show: !0,
72
72
  showMaxLabel: !0,
@@ -78,76 +78,84 @@ function v({ theme: e, formatter: t, labelFormatter: n }) {
78
78
  }
79
79
  };
80
80
  }
81
- function y(t) {
82
- let { theme: n, formatter: o, labelFormatter: s, optionsOverride: c } = t, l = t.series, d = t.selection, f = d && d.length > 0 ? new Set(d) : null;
83
- return (t, d, p) => {
81
+ function b(t) {
82
+ let { theme: n, formatter: s, labelFormatter: c, optionsOverride: l } = t, u = t.series, d = t.selection, p = d && d.length > 0 ? new Set(d) : null;
83
+ return (t, d, m) => {
84
84
  if (t == null) {
85
- let e = v({
85
+ let e = y({
86
86
  theme: n,
87
- formatter: o,
88
- labelFormatter: s
87
+ formatter: s,
88
+ labelFormatter: c
89
89
  });
90
- return c ? i(e, c) : e;
90
+ return l ? i(e, l) : e;
91
91
  }
92
- let m = Array.isArray(d) ? d : [];
93
- if (m.length === 0) return {
92
+ let h = Array.isArray(d) ? d : [];
93
+ if (h.length === 0) return {
94
94
  ...t,
95
95
  dataset: [],
96
96
  series: []
97
97
  };
98
- let h = m.length > 1, g = typeof t.legend == "object" && !Array.isArray(t.legend) ? t.legend : {}, y = typeof t.grid == "object" && !Array.isArray(t.grid) ? t.grid : {}, x = typeof t.tooltip == "object" && !Array.isArray(t.tooltip) ? t.tooltip : {}, S = typeof t.yAxis == "object" && !Array.isArray(t.yAxis) ? t.yAxis : {}, C = Array.isArray(t.series) ? t.series : [], w = C[0] ?? {}, T = p?.formatter, E = p?.labelFormatter, D = 0, O = 1, k = r(t.dataZoom, h), A = typeof y.bottom == "number" ? y.bottom : 24, j = h ? 56 : A, M = k ? j + e.sliderHeight + e.sliderGap : j, N = { color: (e) => {
99
- let t = e.color;
100
- if (!f) return t;
101
- let n = e.value?.name ?? e.name;
102
- return n != null && f.has(n) ? t : _.color.modifyAlpha(t, .15);
103
- } };
98
+ let g = h.length > 1, _ = typeof t.legend == "object" && !Array.isArray(t.legend) ? t.legend : {}, b = typeof t.grid == "object" && !Array.isArray(t.grid) ? t.grid : {}, S = typeof t.tooltip == "object" && !Array.isArray(t.tooltip) ? t.tooltip : {}, C = typeof t.yAxis == "object" && !Array.isArray(t.yAxis) ? t.yAxis : {}, w = Array.isArray(t.series) ? t.series : [], T = w[0] ?? {}, E = m?.formatter, D = m?.labelFormatter, O = 0, k = 1, A = r(t.dataZoom, g), j = typeof b.bottom == "number" ? b.bottom : 24, M = g ? 56 : j, N = A ? M + e.sliderHeight + e.sliderGap : M, P = (e, t) => {
99
+ let r = f({
100
+ theme: n,
101
+ datums: e,
102
+ template: t,
103
+ fallback: (e) => e.color
104
+ });
105
+ return { color: (e) => {
106
+ let t = r(e);
107
+ if (!p) return t;
108
+ let n = e.value?.name ?? e.name;
109
+ return n != null && p.has(n) ? t : v.color.modifyAlpha(t, .15);
110
+ } };
111
+ };
104
112
  return {
105
113
  ...t,
106
- dataset: m.map((e) => ({ source: e })),
107
- series: m.map((e, t) => {
108
- let r = C[t] ?? w, i = a(n, l?.[t]?.color);
114
+ dataset: h.map((e) => ({ source: e })),
115
+ series: h.map((e, t) => {
116
+ let r = w[t] ?? T, i = a(n, u?.[t]?.color);
109
117
  return {
110
118
  ...typeof r == "object" ? r : {},
111
119
  type: "bar",
112
120
  datasetIndex: t,
113
- name: l?.[t]?.name ?? `Series ${t + 1}`,
121
+ name: u?.[t]?.name ?? `Series ${t + 1}`,
114
122
  encode: {
115
123
  x: "name",
116
124
  y: "value"
117
125
  },
118
126
  barMaxWidth: 100,
119
127
  emphasis: { focus: "series" },
120
- itemStyle: N,
128
+ itemStyle: P(e, r),
121
129
  ...i ? { color: i } : {}
122
130
  };
123
131
  }),
124
132
  legend: {
125
- ...g,
126
- show: h
133
+ ..._,
134
+ show: g
127
135
  },
128
136
  grid: {
129
- ...y,
130
- bottom: M
137
+ ...b,
138
+ bottom: N
131
139
  },
132
- ...k ? { dataZoom: k } : {},
140
+ ...A ? { dataZoom: A } : {},
133
141
  yAxis: {
134
- ...S,
135
- min: (e) => (D = e.min < 0 ? u(e.min) : 0, D),
136
- max: (e) => (O = e.max <= 0 ? 1 : u(e.max), O),
142
+ ...C,
143
+ min: (e) => (O = e.min < 0 ? o(e.min) : 0, O),
144
+ max: (e) => (k = e.max <= 0 ? 1 : o(e.max), k),
137
145
  axisLabel: {
138
- ...S.axisLabel ?? {},
139
- formatter: (e) => e !== O && e !== D || e === 0 ? "" : T ? T(e) : String(e)
146
+ ...C.axisLabel ?? {},
147
+ formatter: (e) => e !== k && e !== O || e === 0 ? "" : E ? E(e) : String(e)
140
148
  }
141
149
  },
142
150
  tooltip: {
143
- ...x,
144
- formatter: b(T, E)
151
+ ...S,
152
+ formatter: x(E, D)
145
153
  }
146
154
  };
147
155
  };
148
156
  }
149
- function b(e, t) {
150
- return o((n) => {
157
+ function x(e, t) {
158
+ return l((n) => {
151
159
  let r = n.value?.value, i = typeof r == "number" && e ? e(r) : r ?? "", a = typeof n.marker == "string" ? n.marker : "", o = n.seriesName ? `${n.seriesName}: ` : "", s = t ? String(t(n.name ?? "")) : n.name ?? "";
152
160
  return {
153
161
  name: String(s),
@@ -159,7 +167,7 @@ function b(e, t) {
159
167
  }
160
168
  //#endregion
161
169
  //#region src/widgets/bar/skeleton.tsx
162
- var x = {
170
+ var S = {
163
171
  container: {
164
172
  display: "flex",
165
173
  alignItems: "center",
@@ -191,51 +199,51 @@ var x = {
191
199
  alignItems: "center",
192
200
  gap: ({ spacing: e }) => e(1.5)
193
201
  }
194
- }, S = [
202
+ }, C = [
195
203
  "20%",
196
204
  "40%",
197
205
  "60%",
198
206
  "20%",
199
207
  "80%"
200
208
  ];
201
- function C() {
202
- let e = f(2), t;
203
- e[0] === Symbol.for("react.memo_cache_sentinel") ? (t = /* @__PURE__ */ h(p, {
204
- sx: x.grid,
205
- children: S.map(T)
209
+ function w() {
210
+ let e = p(2), t;
211
+ e[0] === Symbol.for("react.memo_cache_sentinel") ? (t = /* @__PURE__ */ g(m, {
212
+ sx: S.grid,
213
+ children: C.map(E)
206
214
  }), e[0] = t) : t = e[0];
207
215
  let n;
208
- return e[1] === Symbol.for("react.memo_cache_sentinel") ? (n = /* @__PURE__ */ g(p, {
209
- sx: x.container,
210
- children: [t, /* @__PURE__ */ h(p, {
211
- sx: x.legend,
212
- children: [0, 1].map(w)
216
+ return e[1] === Symbol.for("react.memo_cache_sentinel") ? (n = /* @__PURE__ */ _(m, {
217
+ sx: S.container,
218
+ children: [t, /* @__PURE__ */ g(m, {
219
+ sx: S.legend,
220
+ children: [0, 1].map(T)
213
221
  })]
214
222
  }), e[1] = n) : n = e[1], n;
215
223
  }
216
- function w(e) {
217
- return /* @__PURE__ */ g(p, {
218
- sx: x.legendItem,
219
- children: [/* @__PURE__ */ h(m, {
224
+ function T(e) {
225
+ return /* @__PURE__ */ _(m, {
226
+ sx: S.legendItem,
227
+ children: [/* @__PURE__ */ g(h, {
220
228
  variant: "circular",
221
229
  width: 8,
222
230
  height: 8
223
- }), /* @__PURE__ */ h(m, {
231
+ }), /* @__PURE__ */ g(h, {
224
232
  width: 48,
225
233
  height: 8
226
234
  })]
227
235
  }, `legend-${e}`);
228
236
  }
229
- function T(e, t) {
230
- return /* @__PURE__ */ h(m, {
231
- sx: x.bar,
237
+ function E(e, t) {
238
+ return /* @__PURE__ */ g(h, {
239
+ sx: S.bar,
232
240
  variant: "rectangular",
233
241
  height: e
234
242
  }, `bar-${t}`);
235
243
  }
236
244
  //#endregion
237
245
  //#region src/widgets/bar/download.tsx
238
- function E(e) {
246
+ function D(e) {
239
247
  return n(e, t({
240
248
  filename: e.filename,
241
249
  getRows: (t) => {
@@ -249,6 +257,6 @@ function E(e) {
249
257
  }));
250
258
  }
251
259
  //#endregion
252
- export { C as BarSkeleton, v as barOptions, E as createBarDownloadConfig, y as createBarOptionFactory };
260
+ export { w as BarSkeleton, y as barOptions, D as createBarDownloadConfig, b as createBarOptionFactory };
253
261
 
254
262
  //# sourceMappingURL=bar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bar.js","names":["<Box sx={styles.grid}>\n {BAR_HEIGHTS.map((height, i) => (\n <Skeleton\n key={`bar-${i}`}\n sx={styles.bar}\n variant='rectangular'\n height={height}\n />\n ))}\n </Box>","(height, i) => (\n <Skeleton\n key={`bar-${i}`}\n sx={styles.bar}\n variant='rectangular'\n height={height}\n />\n )","<Box sx={styles.container}>\n <Box sx={styles.grid}>\n {BAR_HEIGHTS.map((height, i) => (\n <Skeleton\n key={`bar-${i}`}\n sx={styles.bar}\n variant='rectangular'\n height={height}\n />\n ))}\n </Box>\n <Box sx={styles.legend}>\n {[0, 1].map((i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n ))}\n </Box>\n </Box>","(i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n )","i","_c","ZOOM_LAYOUT","buildCsvDownloadItem","withPngItem","positionDataZoomForLegend","mergeOptions","resolveThemeColor","createTooltipFormatter","buildGridConfig","createTooltipPositioner","buildLegendConfig","niceNum","buildAxisLabelStyle","echarts","barOptions","niceMin","niceMax","theme","buildBarTooltipFormatter","formatter","labelFormatter","v","extent","value","createBarOptionFactory","options","series","selection","selectionSet","option","structural","optionsOverride","seriesArr","data","hasLegend","baseLegend","baseGrid","baseTooltip","baseYAxis","seriesTemplates","broadcastTemplate","liveFormatter","ctx","liveLabelFormatter","dataZoomLayout","fallbackBottom","baseBottom","gridBottom","dimItemStyle","base","params","name","s","template","i","overrideColor","raw","item","formattedValue","marker","seriesName","styles","spacing","BAR_HEIGHTS","BarSkeleton","$","c","t0","Box","_temp","t1","_temp2","Skeleton","i_0","createBarDownloadConfig","args","rows","d"],"sources":["../../src/widgets/bar/options.ts","../../src/widgets/bar/skeleton.tsx","../../src/widgets/bar/download.tsx"],"sourcesContent":["import type { EChartsOption } from 'echarts'\nimport * as echarts from 'echarts'\nimport type { CallbackDataParams } from 'echarts/types/dist/shared'\nimport {\n buildAxisLabelStyle,\n buildGridConfig,\n buildLegendConfig,\n createTooltipFormatter,\n createTooltipPositioner,\n niceNum,\n} from '../utils/option-builders'\nimport { ZOOM_LAYOUT } from '../actions/zoom-toggle'\nimport type { OptionFactory } from '../echart'\nimport { mergeOptions, resolveThemeColor } from '../utils'\nimport { positionDataZoomForLegend } from '../utils/data-zoom-layout'\nimport type {\n BarEChartsOption,\n BarOptionFactoryInput,\n BarOptionsInput,\n BarWidgetData,\n} from './types'\n\n/**\n * Builds the **structural** ECharts option for a bar widget — axes, grid,\n * tooltip styling, themed legend. Intentionally data-agnostic: no series,\n * no dataset, no `legend.show` (those depend on data and are added by the\n * option factory's merge phase). This separation is what lets data-side\n * pipeline transforms (Searcher, RelativeData) drive the rendered chart —\n * the merge happens at render time inside the Echart bridge.\n *\n * Styling matches the v1 `barConfig` look-and-feel: minimal axes (only\n * min/max y-labels rendered inside the plot via `niceNum`), themed tooltip,\n * scroll legend, and CARTO color palette. The y-axis min/max + label\n * formatter and the tooltip formatter are wired here for the no-data case;\n * {@link createBarOptionFactory} re-derives them at fusion time so reactive\n * formatter changes (RelativeData) and stack templates (StackToggle) flow\n * through to the chart.\n */\nexport function barOptions({\n theme,\n formatter,\n labelFormatter,\n}: BarOptionsInput): BarEChartsOption {\n // Closure shared between yAxis min/max callbacks and the label formatter,\n // so only the rounded extents are labelled (matches v1).\n let niceMin = 0\n let niceMax = 1\n\n return {\n grid: {\n left: parseInt(theme.spacing(1)),\n top: parseInt(theme.spacing(3)),\n right: parseInt(theme.spacing(1)),\n // Default: no legend. Merger bumps this when there are >1 series.\n ...buildGridConfig(false, theme),\n containLabel: true,\n },\n tooltip: {\n trigger: 'axis',\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 axisPointer: { type: 'line' },\n position: createTooltipPositioner(theme),\n formatter: buildBarTooltipFormatter(formatter, labelFormatter),\n },\n // Legend styling baked here; `show` is toggled by the merger based on\n // series count.\n legend: {\n ...buildLegendConfig({ hasLegend: false, labelFormatter }),\n },\n axisPointer: { lineStyle: { color: theme.palette.grey[400] } },\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 xAxis: {\n type: 'category',\n axisLine: { show: false },\n axisTick: { show: false },\n axisLabel: {\n ...buildAxisLabelStyle(theme),\n padding: [parseInt(theme.spacing(0.5)), 0, 0, 0],\n margin: 0,\n // `interval: 0` makes every category label a candidate so `hideOverlap`\n // can pack the maximum number that physically fit; the category-axis\n // default (`'auto'`) sub-samples first and shows fewer than fit.\n interval: 0,\n hideOverlap: true,\n ...(labelFormatter && {\n formatter: (v: string | number) => String(labelFormatter(v)),\n }),\n },\n },\n yAxis: {\n type: 'value',\n min: (extent: { min: number }) => {\n niceMin = extent.min < 0 ? niceNum(extent.min) : 0\n return niceMin\n },\n max: (extent: { min: number; max: number }) => {\n niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)\n return niceMax\n },\n axisLine: { show: false },\n axisTick: { show: false },\n splitLine: {\n show: true,\n lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },\n },\n axisLabel: {\n ...buildAxisLabelStyle(theme),\n margin: parseInt(theme.spacing(1)),\n show: true,\n showMaxLabel: true,\n showMinLabel: true,\n verticalAlign: 'bottom',\n inside: true,\n formatter: (value: number) => {\n if (value !== niceMax && value !== niceMin) return ''\n if (value === 0) return ''\n return formatter ? formatter(value) : String(value)\n },\n },\n },\n } as BarEChartsOption\n}\n\n/**\n * Returns the bar widget's {@link OptionFactory} — a single closure that\n * handles BOTH option-construction phases:\n *\n * - **Structural phase** (`option == null`) — builds the theme-aware\n * structural option via {@link barOptions}, optionally merging the\n * consumer-supplied `optionsOverride` on top. Called once by Provider\n * to seed `rawOptions` in the store; configTransforms (StackToggle /\n * ZoomToggle / BrushToggle) then mutate it via the pipeline middleware.\n * - **Merge phase** (`option != null`) — fuses post-pipeline `state.data`\n * (`BarWidgetData`) into the option via the dataset API: one dataset\n * per series, each series referencing its dataset by index, encoded\n * by `name` (x) and `value` (y). Spreads any series-template fields\n * already on the incoming option (e.g. `{ stack: 'total' }` from\n * `addStack`) into every emitted series so configTransforms compose\n * end-to-end. Reactive `ctx.formatter` / `ctx.labelFormatter` drive\n * the y-axis min/max-only label and the tooltip formatter at fusion\n * time so RelativeData's percent formatter flows through without a\n * structural rebuild.\n *\n * Stable identity when the inputs don't change (consumers should wrap the\n * call in `useMemo` keyed on the same inputs).\n */\nexport function createBarOptionFactory(\n options: BarOptionFactoryInput,\n): OptionFactory {\n const { theme, formatter, labelFormatter, optionsOverride } = options\n const series = options.series\n const selection = options.selection\n const selectionSet =\n selection && selection.length > 0\n ? new Set<string | number>(selection)\n : null\n return (option, data, ctx) => {\n // Structural phase: Provider seeds rawOptions with this branch. No data\n // is read; we just emit the theme-aware base (optionally with override).\n if (option == null) {\n const structural = barOptions({ theme, formatter, labelFormatter })\n return optionsOverride\n ? (mergeOptions(\n structural as unknown as Record<string, unknown>,\n optionsOverride as Partial<Record<string, unknown>>,\n ) as EChartsOption)\n : structural\n }\n\n const seriesArr = Array.isArray(data) ? (data as BarWidgetData) : []\n if (seriesArr.length === 0) {\n return { ...option, dataset: [], series: [] }\n }\n const hasLegend = seriesArr.length > 1\n const baseLegend =\n typeof option.legend === 'object' && !Array.isArray(option.legend)\n ? option.legend\n : {}\n const baseGrid =\n typeof option.grid === 'object' && !Array.isArray(option.grid)\n ? option.grid\n : {}\n const baseTooltip =\n typeof option.tooltip === 'object' && !Array.isArray(option.tooltip)\n ? option.tooltip\n : {}\n const baseYAxis =\n typeof option.yAxis === 'object' && !Array.isArray(option.yAxis)\n ? option.yAxis\n : {}\n\n const seriesTemplates = Array.isArray(option.series) ? option.series : []\n const broadcastTemplate = seriesTemplates[0] ?? {}\n\n // Reactive (live store) formatters from ctx — distinct from the\n // closure-time `formatter` / `labelFormatter` captured for the\n // structural-build branch above. RelativeData can install a percent\n // formatter on the store after the factory was constructed; the merge\n // phase reads `ctx` to pick that up.\n const liveFormatter = ctx?.formatter\n const liveLabelFormatter = ctx?.labelFormatter\n\n // Closure shared between the yAxis min/max callbacks and the label\n // formatter, so only the rounded extents are labelled (matches v1).\n // Delegating the extent to ECharts (rather than precomputing scalars\n // from the raw data) is what keeps stacked bars inside the plot: when\n // StackToggle marks the series, ECharts feeds the *post-stack* extent\n // to these callbacks, so `niceNum` rounds the stacked total instead of\n // a single series.\n let niceMin = 0\n let niceMax = 1\n\n // Zoom slider layout: when ZoomToggle has installed `dataZoom`, push the\n // slider above the legend (if any) and reserve room in the grid below.\n const dataZoomLayout = positionDataZoomForLegend(option.dataZoom, hasLegend)\n const fallbackBottom =\n typeof baseGrid.bottom === 'number' ? baseGrid.bottom : 24\n const baseBottom = hasLegend ? 56 : fallbackBottom\n const gridBottom = dataZoomLayout\n ? baseBottom + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap\n : baseBottom\n\n // When a selection is active, dim non-selected bars by routing the\n // resolved palette color through `modifyAlpha`. Per-row `itemStyle` on\n // dataset object-rows is silently ignored when `series.encode` is in\n // play — the callback approach is the standard ECharts pattern for\n // per-data styling derived from a dataset.\n //\n // We *always* emit `itemStyle.color` (a passthrough when nothing is\n // selected), not conditionally — dropping the key between renders\n // would let ECharts' default merge keep the previous callback alive\n // and bars would stay dimmed forever after an external clear. Always\n // emitting lets normal merge swap the callback in place, no\n // `replaceMerge` and no entry-animation flash on selection on/off.\n const dimItemStyle = {\n color: (params: CallbackDataParams) => {\n const base = params.color as string\n if (!selectionSet) return base\n const datum = params.value as { name?: string | number } | undefined\n const name = datum?.name ?? params.name\n return name != null && selectionSet.has(name)\n ? base\n : echarts.color.modifyAlpha(base, 0.15)\n },\n }\n\n return {\n ...option,\n dataset: seriesArr.map((s) => ({ source: s as readonly object[] })),\n series: seriesArr.map((_, i) => {\n const template =\n (seriesTemplates[i] as object | undefined) ??\n (broadcastTemplate as object)\n // Per-series `color` override: ECharts sets `params.color` from\n // `series[i].color` when resolving styles, so the dim callback\n // above keeps working — it just dims the user's colour rather\n // than the palette default.\n const overrideColor = resolveThemeColor(theme, series?.[i]?.color)\n return {\n ...(typeof template === 'object' ? template : {}),\n type: 'bar' as const,\n datasetIndex: i,\n name: series?.[i]?.name ?? `Series ${i + 1}`,\n encode: { x: 'name', y: 'value' },\n barMaxWidth: 100,\n emphasis: { focus: 'series' },\n itemStyle: dimItemStyle,\n ...(overrideColor ? { color: overrideColor } : {}),\n }\n }),\n legend: { ...baseLegend, show: hasLegend },\n grid: {\n ...baseGrid,\n bottom: gridBottom,\n },\n ...(dataZoomLayout ? { dataZoom: dataZoomLayout } : {}),\n yAxis: {\n ...baseYAxis,\n min: (extent: { min: number }) => {\n niceMin = extent.min < 0 ? niceNum(extent.min) : 0\n return niceMin\n },\n max: (extent: { min: number; max: number }) => {\n niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)\n return niceMax\n },\n axisLabel: {\n ...((baseYAxis as { axisLabel?: object }).axisLabel ?? {}),\n formatter: (value: number) => {\n if (value !== niceMax && value !== niceMin) return ''\n if (value === 0) return ''\n return liveFormatter ? liveFormatter(value) : String(value)\n },\n },\n } as EChartsOption['yAxis'],\n tooltip: {\n ...baseTooltip,\n formatter: buildBarTooltipFormatter(liveFormatter, liveLabelFormatter),\n },\n } as EChartsOption\n }\n}\n\nfunction buildBarTooltipFormatter(\n formatter: ((value: number) => string) | undefined,\n labelFormatter: ((value: string | number) => string | number) | undefined,\n) {\n return createTooltipFormatter((item) => {\n const row = item.value as { name?: string | number; value?: number }\n const raw = row?.value\n const formattedValue =\n typeof raw === 'number' && formatter ? formatter(raw) : (raw ?? '')\n const marker = typeof item.marker === 'string' ? item.marker : ''\n const seriesName = item.seriesName ? `${item.seriesName}: ` : ''\n const name = labelFormatter\n ? String(labelFormatter(item.name ?? ''))\n : (item.name ?? '')\n return { name: String(name), seriesName, marker, value: formattedValue }\n })\n}\n","import { Box, Skeleton, type SxProps, type Theme } from '@mui/material'\n\nconst styles = {\n container: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n flexDirection: 'column',\n gap: ({ spacing }) => spacing(1),\n height: ({ spacing }) => spacing(38),\n },\n grid: {\n display: 'flex',\n justifyContent: 'space-between',\n flex: '1 1 auto',\n alignItems: 'flex-end',\n width: '100%',\n },\n bar: {\n flex: 1,\n maxWidth: ({ spacing }) => spacing(12),\n '& + &': {\n marginLeft: ({ spacing }) => spacing(1),\n },\n },\n legend: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(2),\n height: ({ spacing }) => spacing(5),\n },\n legendItem: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(1.5),\n },\n} satisfies Record<string, SxProps<Theme>>\n\nconst BAR_HEIGHTS = ['20%', '40%', '60%', '20%', '80%'] as const\n\n/**\n * Loading state for the Bar widget. Mirrors a bar chart's silhouette — five\n * vertical bars at staggered heights anchored to the bottom, plus a legend\n * stub — so the skeleton reads as \"a bar chart\" rather than a generic list.\n */\nexport function BarSkeleton() {\n return (\n <Box sx={styles.container}>\n <Box sx={styles.grid}>\n {BAR_HEIGHTS.map((height, i) => (\n <Skeleton\n key={`bar-${i}`}\n sx={styles.bar}\n variant='rectangular'\n height={height}\n />\n ))}\n </Box>\n <Box sx={styles.legend}>\n {[0, 1].map((i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n ))}\n </Box>\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n withPngItem,\n type DownloadItem,\n type WidgetDownloadArgs,\n} from '../actions/download'\nimport type { BarWidgetData } from './types'\n\nexport type BarDownloadConfigArgs = WidgetDownloadArgs<BarWidgetData>\n\n/**\n * Builds download items for the Bar widget. Always includes a CSV item with\n * one `name,value` block per series, separated by an empty row when there\n * are multiple. When `getCaptureEl` is given, also prepends a PNG item that\n * rasterises the captured element via `html2canvas`.\n */\nexport function createBarDownloadConfig(\n args: BarDownloadConfigArgs,\n): DownloadItem[] {\n return withPngItem(\n args,\n buildCsvDownloadItem({\n filename: args.filename,\n getRows: (ctx) => {\n const data = args.getData(ctx)\n const rows: unknown[][] = []\n for (const [i, series] of data.entries()) {\n if (i > 0) rows.push([])\n rows.push(['name', 'value'])\n for (const d of series) rows.push([d.name, d.value])\n }\n return rows\n },\n }),\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bar.js","names":["<Box sx={styles.grid}>\n {BAR_HEIGHTS.map((height, i) => (\n <Skeleton\n key={`bar-${i}`}\n sx={styles.bar}\n variant='rectangular'\n height={height}\n />\n ))}\n </Box>","(height, i) => (\n <Skeleton\n key={`bar-${i}`}\n sx={styles.bar}\n variant='rectangular'\n height={height}\n />\n )","<Box sx={styles.container}>\n <Box sx={styles.grid}>\n {BAR_HEIGHTS.map((height, i) => (\n <Skeleton\n key={`bar-${i}`}\n sx={styles.bar}\n variant='rectangular'\n height={height}\n />\n ))}\n </Box>\n <Box sx={styles.legend}>\n {[0, 1].map((i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n ))}\n </Box>\n </Box>","(i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n )","i","_c","ZOOM_LAYOUT","buildCsvDownloadItem","withPngItem","positionDataZoomForLegend","mergeOptions","resolveThemeColor","niceNum","buildLegendConfig","buildAxisLabelStyle","createTooltipFormatter","buildGridConfig","createTooltipPositioner","createItemColorResolver","echarts","barOptions","niceMin","niceMax","theme","buildBarTooltipFormatter","formatter","labelFormatter","v","extent","value","createBarOptionFactory","options","series","selection","selectionSet","option","structural","optionsOverride","seriesArr","data","hasLegend","baseLegend","baseGrid","baseTooltip","baseYAxis","seriesTemplates","broadcastTemplate","liveFormatter","ctx","liveLabelFormatter","dataZoomLayout","fallbackBottom","baseBottom","gridBottom","makeDimItemStyle","baseColor","params","base","name","s","template","i","overrideColor","raw","item","formattedValue","marker","seriesName","styles","spacing","BAR_HEIGHTS","BarSkeleton","$","c","t0","Box","_temp","t1","_temp2","Skeleton","i_0","createBarDownloadConfig","args","rows","d"],"sources":["../../src/widgets/bar/options.ts","../../src/widgets/bar/skeleton.tsx","../../src/widgets/bar/download.tsx"],"sourcesContent":["import type { EChartsOption } from 'echarts'\nimport * as echarts from 'echarts'\nimport type { CallbackDataParams } from 'echarts/types/dist/shared'\nimport {\n buildAxisLabelStyle,\n buildGridConfig,\n buildLegendConfig,\n createTooltipFormatter,\n createTooltipPositioner,\n niceNum,\n} from '../utils/option-builders'\nimport { ZOOM_LAYOUT } from '../actions/zoom-toggle'\nimport type { OptionFactory } from '../echart'\nimport { mergeOptions, resolveThemeColor } from '../utils'\nimport { createItemColorResolver } from '../utils/item-color'\nimport { positionDataZoomForLegend } from '../utils/data-zoom-layout'\nimport type {\n BarEChartsOption,\n BarOptionFactoryInput,\n BarOptionsInput,\n BarWidgetData,\n} from './types'\n\n/**\n * Builds the **structural** ECharts option for a bar widget — axes, grid,\n * tooltip styling, themed legend. Intentionally data-agnostic: no series,\n * no dataset, no `legend.show` (those depend on data and are added by the\n * option factory's merge phase). This separation is what lets data-side\n * pipeline transforms (Searcher, RelativeData) drive the rendered chart —\n * the merge happens at render time inside the Echart bridge.\n *\n * Styling matches the v1 `barConfig` look-and-feel: minimal axes (only\n * min/max y-labels rendered inside the plot via `niceNum`), themed tooltip,\n * scroll legend, and CARTO color palette. The y-axis min/max + label\n * formatter and the tooltip formatter are wired here for the no-data case;\n * {@link createBarOptionFactory} re-derives them at fusion time so reactive\n * formatter changes (RelativeData) and stack templates (StackToggle) flow\n * through to the chart.\n */\nexport function barOptions({\n theme,\n formatter,\n labelFormatter,\n}: BarOptionsInput): BarEChartsOption {\n // Closure shared between yAxis min/max callbacks and the label formatter,\n // so only the rounded extents are labelled (matches v1).\n let niceMin = 0\n let niceMax = 1\n\n return {\n grid: {\n left: parseInt(theme.spacing(1)),\n top: parseInt(theme.spacing(3)),\n right: parseInt(theme.spacing(1)),\n // Default: no legend. Merger bumps this when there are >1 series.\n ...buildGridConfig(false, theme),\n containLabel: true,\n },\n tooltip: {\n trigger: 'axis',\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 axisPointer: { type: 'line' },\n position: createTooltipPositioner(theme),\n formatter: buildBarTooltipFormatter(formatter, labelFormatter),\n },\n // Legend styling baked here; `show` is toggled by the merger based on\n // series count.\n legend: {\n ...buildLegendConfig({ hasLegend: false, labelFormatter }),\n },\n axisPointer: { lineStyle: { color: theme.palette.grey[400] } },\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 xAxis: {\n type: 'category',\n axisLine: { show: false },\n axisTick: { show: false },\n axisLabel: {\n ...buildAxisLabelStyle(theme),\n padding: [parseInt(theme.spacing(0.5)), 0, 0, 0],\n margin: 0,\n // `interval: 0` makes every category label a candidate so `hideOverlap`\n // can pack the maximum number that physically fit; the category-axis\n // default (`'auto'`) sub-samples first and shows fewer than fit.\n interval: 0,\n hideOverlap: true,\n ...(labelFormatter && {\n formatter: (v: string | number) => String(labelFormatter(v)),\n }),\n },\n },\n yAxis: {\n type: 'value',\n min: (extent: { min: number }) => {\n niceMin = extent.min < 0 ? niceNum(extent.min) : 0\n return niceMin\n },\n max: (extent: { min: number; max: number }) => {\n niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)\n return niceMax\n },\n axisLine: { show: false },\n axisTick: { show: false },\n splitLine: {\n show: true,\n lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },\n },\n axisLabel: {\n ...buildAxisLabelStyle(theme),\n margin: parseInt(theme.spacing(1)),\n show: true,\n showMaxLabel: true,\n showMinLabel: true,\n verticalAlign: 'bottom',\n inside: true,\n formatter: (value: number) => {\n if (value !== niceMax && value !== niceMin) return ''\n if (value === 0) return ''\n return formatter ? formatter(value) : String(value)\n },\n },\n },\n } as BarEChartsOption\n}\n\n/**\n * Returns the bar widget's {@link OptionFactory} — a single closure that\n * handles BOTH option-construction phases:\n *\n * - **Structural phase** (`option == null`) — builds the theme-aware\n * structural option via {@link barOptions}, optionally merging the\n * consumer-supplied `optionsOverride` on top. Called once by Provider\n * to seed `rawOptions` in the store; configTransforms (StackToggle /\n * ZoomToggle / BrushToggle) then mutate it via the pipeline middleware.\n * - **Merge phase** (`option != null`) — fuses post-pipeline `state.data`\n * (`BarWidgetData`) into the option via the dataset API: one dataset\n * per series, each series referencing its dataset by index, encoded\n * by `name` (x) and `value` (y). Spreads any series-template fields\n * already on the incoming option (e.g. `{ stack: 'total' }` from\n * `addStack`) into every emitted series so configTransforms compose\n * end-to-end. Reactive `ctx.formatter` / `ctx.labelFormatter` drive\n * the y-axis min/max-only label and the tooltip formatter at fusion\n * time so RelativeData's percent formatter flows through without a\n * structural rebuild.\n *\n * Stable identity when the inputs don't change (consumers should wrap the\n * call in `useMemo` keyed on the same inputs).\n */\nexport function createBarOptionFactory(\n options: BarOptionFactoryInput,\n): OptionFactory {\n const { theme, formatter, labelFormatter, optionsOverride } = options\n const series = options.series\n const selection = options.selection\n const selectionSet =\n selection && selection.length > 0\n ? new Set<string | number>(selection)\n : null\n return (option, data, ctx) => {\n // Structural phase: Provider seeds rawOptions with this branch. No data\n // is read; we just emit the theme-aware base (optionally with override).\n if (option == null) {\n const structural = barOptions({ theme, formatter, labelFormatter })\n return optionsOverride\n ? (mergeOptions(\n structural as unknown as Record<string, unknown>,\n optionsOverride as Partial<Record<string, unknown>>,\n ) as EChartsOption)\n : structural\n }\n\n const seriesArr = Array.isArray(data) ? (data as BarWidgetData) : []\n if (seriesArr.length === 0) {\n return { ...option, dataset: [], series: [] }\n }\n const hasLegend = seriesArr.length > 1\n const baseLegend =\n typeof option.legend === 'object' && !Array.isArray(option.legend)\n ? option.legend\n : {}\n const baseGrid =\n typeof option.grid === 'object' && !Array.isArray(option.grid)\n ? option.grid\n : {}\n const baseTooltip =\n typeof option.tooltip === 'object' && !Array.isArray(option.tooltip)\n ? option.tooltip\n : {}\n const baseYAxis =\n typeof option.yAxis === 'object' && !Array.isArray(option.yAxis)\n ? option.yAxis\n : {}\n\n const seriesTemplates = Array.isArray(option.series) ? option.series : []\n const broadcastTemplate = seriesTemplates[0] ?? {}\n\n // Reactive (live store) formatters from ctx — distinct from the\n // closure-time `formatter` / `labelFormatter` captured for the\n // structural-build branch above. RelativeData can install a percent\n // formatter on the store after the factory was constructed; the merge\n // phase reads `ctx` to pick that up.\n const liveFormatter = ctx?.formatter\n const liveLabelFormatter = ctx?.labelFormatter\n\n // Closure shared between the yAxis min/max callbacks and the label\n // formatter, so only the rounded extents are labelled (matches v1).\n // Delegating the extent to ECharts (rather than precomputing scalars\n // from the raw data) is what keeps stacked bars inside the plot: when\n // StackToggle marks the series, ECharts feeds the *post-stack* extent\n // to these callbacks, so `niceNum` rounds the stacked total instead of\n // a single series.\n let niceMin = 0\n let niceMax = 1\n\n // Zoom slider layout: when ZoomToggle has installed `dataZoom`, push the\n // slider above the legend (if any) and reserve room in the grid below.\n const dataZoomLayout = positionDataZoomForLegend(option.dataZoom, hasLegend)\n const fallbackBottom =\n typeof baseGrid.bottom === 'number' ? baseGrid.bottom : 24\n const baseBottom = hasLegend ? 56 : fallbackBottom\n const gridBottom = dataZoomLayout\n ? baseBottom + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap\n : baseBottom\n\n // When a selection is active, dim non-selected bars by routing the\n // item's base colour through `modifyAlpha`. Per-row `itemStyle` on\n // dataset object-rows is silently ignored when `series.encode` is in\n // play — the callback approach is the standard ECharts pattern for\n // per-data styling derived from a dataset. The base colour is the\n // datum's `color`, else the template's `itemStyle.color`, else the\n // series colour / palette (`params.color`).\n //\n // We *always* emit `itemStyle.color` (a passthrough when nothing is\n // selected), not conditionally — dropping the key between renders\n // would let ECharts' default merge keep the previous callback alive\n // and bars would stay dimmed forever after an external clear. Always\n // emitting lets normal merge swap the callback in place, no\n // `replaceMerge` and no entry-animation flash on selection on/off.\n const makeDimItemStyle = (datums: readonly object[], template: unknown) => {\n const baseColor = createItemColorResolver({\n theme,\n datums,\n template,\n fallback: (params) => params.color as string,\n })\n return {\n color: (params: CallbackDataParams) => {\n const base = baseColor(params)\n if (!selectionSet) return base\n const datum = params.value as { name?: string | number } | undefined\n const name = datum?.name ?? params.name\n return name != null && selectionSet.has(name)\n ? base\n : echarts.color.modifyAlpha(base, 0.15)\n },\n }\n }\n\n return {\n ...option,\n dataset: seriesArr.map((s) => ({ source: s as readonly object[] })),\n series: seriesArr.map((s, i) => {\n const template =\n (seriesTemplates[i] as object | undefined) ??\n (broadcastTemplate as object)\n // Per-series `color` override: ECharts sets `params.color` from\n // `series[i].color` when resolving styles, so the dim callback\n // above keeps working — it just dims the user's colour rather\n // than the palette default.\n const overrideColor = resolveThemeColor(theme, series?.[i]?.color)\n return {\n ...(typeof template === 'object' ? template : {}),\n type: 'bar' as const,\n datasetIndex: i,\n name: series?.[i]?.name ?? `Series ${i + 1}`,\n encode: { x: 'name', y: 'value' },\n barMaxWidth: 100,\n emphasis: { focus: 'series' },\n itemStyle: makeDimItemStyle(s, template),\n ...(overrideColor ? { color: overrideColor } : {}),\n }\n }),\n legend: { ...baseLegend, show: hasLegend },\n grid: {\n ...baseGrid,\n bottom: gridBottom,\n },\n ...(dataZoomLayout ? { dataZoom: dataZoomLayout } : {}),\n yAxis: {\n ...baseYAxis,\n min: (extent: { min: number }) => {\n niceMin = extent.min < 0 ? niceNum(extent.min) : 0\n return niceMin\n },\n max: (extent: { min: number; max: number }) => {\n niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)\n return niceMax\n },\n axisLabel: {\n ...((baseYAxis as { axisLabel?: object }).axisLabel ?? {}),\n formatter: (value: number) => {\n if (value !== niceMax && value !== niceMin) return ''\n if (value === 0) return ''\n return liveFormatter ? liveFormatter(value) : String(value)\n },\n },\n } as EChartsOption['yAxis'],\n tooltip: {\n ...baseTooltip,\n formatter: buildBarTooltipFormatter(liveFormatter, liveLabelFormatter),\n },\n } as EChartsOption\n }\n}\n\nfunction buildBarTooltipFormatter(\n formatter: ((value: number) => string) | undefined,\n labelFormatter: ((value: string | number) => string | number) | undefined,\n) {\n return createTooltipFormatter((item) => {\n const row = item.value as { name?: string | number; value?: number }\n const raw = row?.value\n const formattedValue =\n typeof raw === 'number' && formatter ? formatter(raw) : (raw ?? '')\n const marker = typeof item.marker === 'string' ? item.marker : ''\n const seriesName = item.seriesName ? `${item.seriesName}: ` : ''\n const name = labelFormatter\n ? String(labelFormatter(item.name ?? ''))\n : (item.name ?? '')\n return { name: String(name), seriesName, marker, value: formattedValue }\n })\n}\n","import { Box, Skeleton, type SxProps, type Theme } from '@mui/material'\n\nconst styles = {\n container: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n flexDirection: 'column',\n gap: ({ spacing }) => spacing(1),\n height: ({ spacing }) => spacing(38),\n },\n grid: {\n display: 'flex',\n justifyContent: 'space-between',\n flex: '1 1 auto',\n alignItems: 'flex-end',\n width: '100%',\n },\n bar: {\n flex: 1,\n maxWidth: ({ spacing }) => spacing(12),\n '& + &': {\n marginLeft: ({ spacing }) => spacing(1),\n },\n },\n legend: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(2),\n height: ({ spacing }) => spacing(5),\n },\n legendItem: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(1.5),\n },\n} satisfies Record<string, SxProps<Theme>>\n\nconst BAR_HEIGHTS = ['20%', '40%', '60%', '20%', '80%'] as const\n\n/**\n * Loading state for the Bar widget. Mirrors a bar chart's silhouette — five\n * vertical bars at staggered heights anchored to the bottom, plus a legend\n * stub — so the skeleton reads as \"a bar chart\" rather than a generic list.\n */\nexport function BarSkeleton() {\n return (\n <Box sx={styles.container}>\n <Box sx={styles.grid}>\n {BAR_HEIGHTS.map((height, i) => (\n <Skeleton\n key={`bar-${i}`}\n sx={styles.bar}\n variant='rectangular'\n height={height}\n />\n ))}\n </Box>\n <Box sx={styles.legend}>\n {[0, 1].map((i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n ))}\n </Box>\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n withPngItem,\n type DownloadItem,\n type WidgetDownloadArgs,\n} from '../actions/download'\nimport type { BarWidgetData } from './types'\n\nexport type BarDownloadConfigArgs = WidgetDownloadArgs<BarWidgetData>\n\n/**\n * Builds download items for the Bar widget. Always includes a CSV item with\n * one `name,value` block per series, separated by an empty row when there\n * are multiple. When `getCaptureEl` is given, also prepends a PNG item that\n * rasterises the captured element via `html2canvas`.\n */\nexport function createBarDownloadConfig(\n args: BarDownloadConfigArgs,\n): DownloadItem[] {\n return withPngItem(\n args,\n buildCsvDownloadItem({\n filename: args.filename,\n getRows: (ctx) => {\n const data = args.getData(ctx)\n const rows: unknown[][] = []\n for (const [i, series] of data.entries()) {\n if (i > 0) rows.push([])\n rows.push(['name', 'value'])\n for (const d of series) rows.push([d.name, d.value])\n }\n return rows\n },\n }),\n )\n}\n"],"mappings":"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"}