@carto/ps-react-ui 6.1.1 → 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 (119) hide show
  1. package/dist/{actions-BWlS5tpP.js → actions-CkxKe8-J.js} +57 -47
  2. package/dist/actions-CkxKe8-J.js.map +1 -0
  3. package/dist/category-DULnoxvk.js +933 -0
  4. package/dist/category-DULnoxvk.js.map +1 -0
  5. package/dist/chat.js +1 -1
  6. package/dist/chat.js.map +1 -1
  7. package/dist/components-CTUpdQuj.js.map +1 -1
  8. package/dist/download-B4sykOFm.js.map +1 -1
  9. package/dist/{echart-CV8F50gn.js → echart-ysYFLa_T.js} +2 -2
  10. package/dist/echart-ysYFLa_T.js.map +1 -0
  11. package/dist/formula-DJS-JLpk.js.map +1 -1
  12. package/dist/{option-builders-DQivvvbb.js → item-color-B7xkIpDZ.js} +26 -9
  13. package/dist/item-color-B7xkIpDZ.js.map +1 -0
  14. package/dist/legend.js.map +1 -1
  15. package/dist/{markdown-Bn2nKCbn.js → markdown-DmvLi3vx.js} +2 -2
  16. package/dist/markdown-DmvLi3vx.js.map +1 -0
  17. package/dist/{markdown-content-kYNLOX0T.js → markdown-content-BpAH_V6S.js} +5 -4
  18. package/dist/markdown-content-BpAH_V6S.js.map +1 -0
  19. package/dist/range-BpU2zBmq.js.map +1 -1
  20. package/dist/smart-tooltip-Dc_rHhyI.js.map +1 -1
  21. package/dist/spread-CQwFIwuz.js.map +1 -1
  22. package/dist/stores-DcBOZlU3.js.map +1 -1
  23. package/dist/stores-mad-9yFn.js.map +1 -1
  24. package/dist/styles-BCEBm7xh.js.map +1 -1
  25. package/dist/table-DEdW_fDj.js.map +1 -1
  26. package/dist/types/widgets/bar/types.d.ts +6 -0
  27. package/dist/types/widgets/category/category-ui.d.ts +10 -2
  28. package/dist/types/widgets/category/category.d.ts +7 -1
  29. package/dist/types/widgets/category/components/category-bar-stacked.d.ts +8 -1
  30. package/dist/types/widgets/category/components/category-bar.d.ts +24 -2
  31. package/dist/types/widgets/category/components/category-row-multi.d.ts +3 -1
  32. package/dist/types/widgets/category/components/category-row-single.d.ts +3 -1
  33. package/dist/types/widgets/category/components/category-row-stacked.d.ts +10 -1
  34. package/dist/types/widgets/category/style.d.ts +33 -6
  35. package/dist/types/widgets/histogram/bins.d.ts +7 -0
  36. package/dist/types/widgets/histogram/download.d.ts +2 -2
  37. package/dist/types/widgets/histogram/index.d.ts +2 -1
  38. package/dist/types/widgets/histogram/options.d.ts +1 -1
  39. package/dist/types/widgets/histogram/transforms.d.ts +5 -4
  40. package/dist/types/widgets/histogram/types.d.ts +22 -5
  41. package/dist/types/widgets/index.d.ts +1 -1
  42. package/dist/types/widgets/pie/types.d.ts +6 -0
  43. package/dist/types/widgets/scatterplot/download.d.ts +2 -2
  44. package/dist/types/widgets/scatterplot/index.d.ts +2 -1
  45. package/dist/types/widgets/scatterplot/points.d.ts +7 -0
  46. package/dist/types/widgets/scatterplot/transforms.d.ts +4 -3
  47. package/dist/types/widgets/scatterplot/types.d.ts +21 -2
  48. package/dist/types/widgets/timeseries/types.d.ts +6 -0
  49. package/dist/types/widgets/utils/item-color.d.ts +26 -0
  50. package/dist/utils-C-eWwOhE.js.map +1 -1
  51. package/dist/widgets/actions.js +1 -1
  52. package/dist/widgets/bar.js +78 -70
  53. package/dist/widgets/bar.js.map +1 -1
  54. package/dist/widgets/category.js +1 -1
  55. package/dist/widgets/echart.js +1 -1
  56. package/dist/widgets/histogram.js +116 -85
  57. package/dist/widgets/histogram.js.map +1 -1
  58. package/dist/widgets/markdown.js +2 -2
  59. package/dist/widgets/pie.js +109 -90
  60. package/dist/widgets/pie.js.map +1 -1
  61. package/dist/widgets/scatterplot.js +131 -92
  62. package/dist/widgets/scatterplot.js.map +1 -1
  63. package/dist/widgets/timeseries.js +82 -74
  64. package/dist/widgets/timeseries.js.map +1 -1
  65. package/dist/widgets.js +5 -5
  66. package/dist/widgets.js.map +1 -1
  67. package/dist/zoom-toggle-MmLjMTEw.js.map +1 -1
  68. package/package.json +2 -2
  69. package/src/widgets/actions/fullscreen/fullscreen-store.test.tsx +77 -13
  70. package/src/widgets/actions/fullscreen/fullscreen.tsx +48 -5
  71. package/src/widgets/bar/options.test.ts +106 -0
  72. package/src/widgets/bar/options.ts +25 -14
  73. package/src/widgets/bar/types.ts +6 -0
  74. package/src/widgets/category/category-ui.test.tsx +139 -0
  75. package/src/widgets/category/category-ui.tsx +64 -11
  76. package/src/widgets/category/category.test.tsx +67 -0
  77. package/src/widgets/category/category.tsx +32 -15
  78. package/src/widgets/category/components/category-bar-stacked.test.tsx +18 -0
  79. package/src/widgets/category/components/category-bar-stacked.tsx +42 -29
  80. package/src/widgets/category/components/category-bar.test.tsx +66 -0
  81. package/src/widgets/category/components/category-bar.tsx +65 -9
  82. package/src/widgets/category/components/category-row-multi.tsx +21 -0
  83. package/src/widgets/category/components/category-row-single.tsx +4 -0
  84. package/src/widgets/category/components/category-row-stacked.tsx +24 -1
  85. package/src/widgets/category/style.ts +58 -14
  86. package/src/widgets/histogram/bins.ts +22 -0
  87. package/src/widgets/histogram/download.test.ts +10 -0
  88. package/src/widgets/histogram/download.ts +7 -3
  89. package/src/widgets/histogram/index.ts +3 -0
  90. package/src/widgets/histogram/options.test.ts +62 -0
  91. package/src/widgets/histogram/options.ts +38 -17
  92. package/src/widgets/histogram/transforms.test.ts +21 -7
  93. package/src/widgets/histogram/transforms.ts +26 -12
  94. package/src/widgets/histogram/types.ts +25 -5
  95. package/src/widgets/index.ts +6 -1
  96. package/src/widgets/pie/options.test.ts +91 -0
  97. package/src/widgets/pie/options.ts +50 -20
  98. package/src/widgets/pie/types.ts +6 -0
  99. package/src/widgets/scatterplot/download.test.ts +9 -0
  100. package/src/widgets/scatterplot/download.ts +5 -3
  101. package/src/widgets/scatterplot/index.ts +3 -0
  102. package/src/widgets/scatterplot/options.test.ts +78 -0
  103. package/src/widgets/scatterplot/options.ts +35 -11
  104. package/src/widgets/scatterplot/points.ts +35 -0
  105. package/src/widgets/scatterplot/transforms.test.ts +19 -0
  106. package/src/widgets/scatterplot/transforms.ts +23 -18
  107. package/src/widgets/scatterplot/types.ts +25 -2
  108. package/src/widgets/timeseries/options.test.ts +65 -0
  109. package/src/widgets/timeseries/options.ts +31 -14
  110. package/src/widgets/timeseries/types.ts +6 -0
  111. package/src/widgets/utils/item-color.test.ts +74 -0
  112. package/src/widgets/utils/item-color.ts +55 -0
  113. package/dist/actions-BWlS5tpP.js.map +0 -1
  114. package/dist/category-alzjKzvQ.js +0 -839
  115. package/dist/category-alzjKzvQ.js.map +0 -1
  116. package/dist/echart-CV8F50gn.js.map +0 -1
  117. package/dist/markdown-Bn2nKCbn.js.map +0 -1
  118. package/dist/markdown-content-kYNLOX0T.js.map +0 -1
  119. package/dist/option-builders-DQivvvbb.js.map +0 -1
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest'
2
+ import * as echarts from 'echarts'
2
3
  import { createTheme, type Theme } from '@mui/material'
3
4
  import { createTimeseriesOptionFactory, timeseriesOptions } from './options'
4
5
 
@@ -397,3 +398,67 @@ describe('createTimeseriesOptionFactory', () => {
397
398
  expect(out.grid.bottom).toBe(96)
398
399
  })
399
400
  })
401
+
402
+ describe('createTimeseriesOptionFactory — per-item colour', () => {
403
+ interface Out {
404
+ series: {
405
+ showSymbol: boolean
406
+ itemStyle: { color: (p: unknown) => string }
407
+ }[]
408
+ }
409
+ const data = [
410
+ [
411
+ { name: 1, value: 1, color: '#00ff00' },
412
+ { name: 2, value: 2 },
413
+ ],
414
+ ]
415
+ const p = (dataIndex: number, name: number) => ({
416
+ dataIndex,
417
+ color: '#0000ff',
418
+ value: { name },
419
+ })
420
+ const dim = (c: string) => echarts.color.modifyAlpha(c, 0.15)
421
+
422
+ it('datum colour wins over the series colour; template next', () => {
423
+ const merge = createTimeseriesOptionFactory({
424
+ theme,
425
+ series: [{ name: 'S', color: '#0000ff' }],
426
+ })
427
+ const out = merge(
428
+ { series: [{ type: 'line', itemStyle: { color: '#123456' } }] },
429
+ data,
430
+ ) as Out
431
+ const colorFn = out.series[0]!.itemStyle.color
432
+ expect(colorFn(p(0, 1))).toBe('#00ff00')
433
+ expect(colorFn(p(1, 2))).toBe('#123456')
434
+ })
435
+
436
+ it('calls a function template itemStyle.color', () => {
437
+ const factory = createTimeseriesOptionFactory({
438
+ theme,
439
+ optionsOverride: {
440
+ series: [{ type: 'line', itemStyle: { color: () => '#ff0000' } }],
441
+ },
442
+ })
443
+ const out = factory(factory(undefined, undefined), [
444
+ [{ name: 1, value: 1 }],
445
+ ]) as Out
446
+ expect(out.series[0]!.itemStyle.color(p(0, 1))).toBe('#ff0000')
447
+ })
448
+
449
+ it('dims item colours outside the selection', () => {
450
+ const merge = createTimeseriesOptionFactory({ theme, selection: [2] })
451
+ const out = merge({}, data) as Out
452
+ const colorFn = out.series[0]!.itemStyle.color
453
+ expect(colorFn(p(0, 1))).toBe(dim('#00ff00'))
454
+ expect(colorFn(p(1, 2))).toBe('#0000ff')
455
+ })
456
+
457
+ it('shows symbols when a point has its own colour, not otherwise', () => {
458
+ const merge = createTimeseriesOptionFactory({ theme })
459
+ expect((merge({}, data) as Out).series[0]!.showSymbol).toBe(true)
460
+ const plain = merge({}, [[{ name: 1, value: 1 }]]) as Out
461
+ expect(plain.series[0]!.showSymbol).toBe(false)
462
+ expect(plain.series[0]!.itemStyle.color(p(0, 1))).toBe('#0000ff')
463
+ })
464
+ })
@@ -12,6 +12,7 @@ import {
12
12
  import { ZOOM_LAYOUT } from '../actions/zoom-toggle'
13
13
  import type { OptionFactory } from '../echart'
14
14
  import { mergeOptions, resolveThemeColor } from '../utils'
15
+ import { createItemColorResolver } from '../utils/item-color'
15
16
  import { positionDataZoomForLegend } from '../utils/data-zoom-layout'
16
17
  import type {
17
18
  TimeseriesEChartsOption,
@@ -237,23 +238,39 @@ export function createTimeseriesOptionFactory(
237
238
  // and points would stay dimmed forever after an external clear.
238
239
  // Always emitting lets normal merge swap the callback in place, no
239
240
  // `replaceMerge` and no entry-animation flash on selection on/off.
240
- const dimItemStyle = {
241
- color: (params: CallbackDataParams) => {
242
- const datum = params.value as
243
- { name?: Date | number | string } | undefined
244
- const raw = datum?.name
245
- const base = params.color as string
246
- if (!selectionSet || raw == null) return base
247
- return selectionSet.has(normalizeName(raw))
248
- ? base
249
- : echarts.color.modifyAlpha(base, 0.15)
250
- },
241
+ //
242
+ // The base colour is the point's own `color`, else the template's
243
+ // `itemStyle.color`, else the series colour / palette (`params.color`).
244
+ const makeDimItemStyle = (datums: readonly object[], template: unknown) => {
245
+ const baseColor = createItemColorResolver({
246
+ theme,
247
+ datums,
248
+ template,
249
+ fallback: (params) => params.color as string,
250
+ })
251
+ return {
252
+ color: (params: CallbackDataParams) => {
253
+ const datum = params.value as
254
+ { name?: Date | number | string } | undefined
255
+ const raw = datum?.name
256
+ const base = baseColor(params)
257
+ if (!selectionSet || raw == null) return base
258
+ return selectionSet.has(normalizeName(raw))
259
+ ? base
260
+ : echarts.color.modifyAlpha(base, 0.15)
261
+ },
262
+ }
251
263
  }
264
+ // Per-point colours only show on markers, so surface them whenever a
265
+ // point carries its own `color` (same reason as the selection case).
266
+ const hasDatumColor = seriesArr.some((s) =>
267
+ s.some((d) => typeof d?.color === 'string' && d.color !== ''),
268
+ )
252
269
 
253
270
  return {
254
271
  ...option,
255
272
  dataset: seriesArr.map((s) => ({ source: s as readonly object[] })),
256
- series: seriesArr.map((_, i) => {
273
+ series: seriesArr.map((s, i) => {
257
274
  const template =
258
275
  (seriesTemplates[i] as object | undefined) ??
259
276
  (broadcastTemplate as object)
@@ -271,10 +288,10 @@ export function createTimeseriesOptionFactory(
271
288
  // When a selection is active, surface markers so the per-point
272
289
  // color callback has something to dim — a continuous line would
273
290
  // hide the visual selection feedback.
274
- showSymbol: selectionSet != null,
291
+ showSymbol: selectionSet != null || hasDatumColor,
275
292
  ...(area ? { areaStyle: {} } : {}),
276
293
  emphasis: { focus: 'series' },
277
- itemStyle: dimItemStyle,
294
+ itemStyle: makeDimItemStyle(s, template),
278
295
  ...(overrideColor
279
296
  ? { color: overrideColor, lineStyle: { color: overrideColor } }
280
297
  : {}),
@@ -10,6 +10,12 @@ import type { WidgetSeries } from '../types'
10
10
  export interface TimeseriesDatum {
11
11
  name: Date | number | string
12
12
  value: number
13
+ /**
14
+ * Optional colour for this item (CSS colour or theme palette path such as
15
+ * `'primary.main'`). Wins over the template's `itemStyle.color` and the
16
+ * series colour; selection dimming still applies on top.
17
+ */
18
+ color?: string
13
19
  }
14
20
 
15
21
  /** Timeseries widget data — one array of points per series. */
@@ -0,0 +1,74 @@
1
+ import { describe, it, expect, vi } from 'vitest'
2
+ import { createTheme } from '@mui/material'
3
+ import type { CallbackDataParams } from 'echarts/types/dist/shared'
4
+ import { createItemColorResolver } from './item-color'
5
+
6
+ const theme = createTheme({ palette: { primary: { main: '#1976d2' } } })
7
+ const params = (dataIndex: number) =>
8
+ ({ dataIndex, color: '#fallback' }) as unknown as CallbackDataParams
9
+ const fallback = (p: CallbackDataParams) => p.color as string
10
+
11
+ describe('createItemColorResolver', () => {
12
+ it('uses the datum colour first', () => {
13
+ const resolve = createItemColorResolver({
14
+ theme,
15
+ datums: [{ color: '#00ff00' }],
16
+ template: { itemStyle: { color: '#123456' } },
17
+ fallback,
18
+ })
19
+ expect(resolve(params(0))).toBe('#00ff00')
20
+ })
21
+
22
+ it('uses a string template itemStyle.color when the datum has none', () => {
23
+ const resolve = createItemColorResolver({
24
+ theme,
25
+ datums: [{}, 3],
26
+ template: { itemStyle: { color: '#123456' } },
27
+ fallback,
28
+ })
29
+ expect(resolve(params(0))).toBe('#123456')
30
+ expect(resolve(params(1))).toBe('#123456')
31
+ })
32
+
33
+ it('calls a function template itemStyle.color with the ECharts params', () => {
34
+ const color = vi.fn(() => '#abcdef')
35
+ const resolve = createItemColorResolver({
36
+ theme,
37
+ datums: [{}],
38
+ template: { itemStyle: { color } },
39
+ fallback,
40
+ })
41
+ const p = params(0)
42
+ expect(resolve(p)).toBe('#abcdef')
43
+ expect(color).toHaveBeenCalledWith(p)
44
+ })
45
+
46
+ it('falls back when neither datum nor template give a colour', () => {
47
+ const resolve = createItemColorResolver({
48
+ theme,
49
+ datums: [{ value: 1 }],
50
+ template: { itemStyle: { color: () => undefined } },
51
+ fallback,
52
+ })
53
+ expect(resolve(params(0))).toBe('#fallback')
54
+ expect(resolve(params(5))).toBe('#fallback')
55
+ const noTemplate = createItemColorResolver({
56
+ theme,
57
+ datums: [],
58
+ template: undefined,
59
+ fallback,
60
+ })
61
+ expect(noTemplate(params(0))).toBe('#fallback')
62
+ })
63
+
64
+ it('resolves theme palette paths on datum and template colours', () => {
65
+ const resolve = createItemColorResolver({
66
+ theme,
67
+ datums: [{ color: 'primary.main' }, {}],
68
+ template: { itemStyle: { color: () => 'primary.main' } },
69
+ fallback,
70
+ })
71
+ expect(resolve(params(0))).toBe('#1976d2')
72
+ expect(resolve(params(1))).toBe('#1976d2')
73
+ })
74
+ })
@@ -0,0 +1,55 @@
1
+ import type { Theme } from '@mui/material'
2
+ import type { CallbackDataParams } from 'echarts/types/dist/shared'
3
+ import { resolveThemeColor } from './resolve-theme-color'
4
+
5
+ /** ECharts `itemStyle.color` callback, as emitted by the chart widgets. */
6
+ export type ItemColorCallback = (params: CallbackDataParams) => string
7
+
8
+ /**
9
+ * Builds the callback that resolves the **base** colour of every item of one
10
+ * series, before any selection dimming. Priority:
11
+ *
12
+ * 1. the datum's own `color` (`datums[params.dataIndex].color`);
13
+ * 2. the consumer's `template.itemStyle.color` (from `optionsOverride`):
14
+ * a string is used as is, a function is called with the ECharts params;
15
+ * 3. `fallback` — the widget's default (series colour / palette).
16
+ *
17
+ * The datum is looked up by `params.dataIndex` in the widget's own data
18
+ * rather than read off `params.data`, so it works whatever the dataset row
19
+ * shape is (object rows, `[label, count]` tuples, `[x, y]` tuples).
20
+ *
21
+ * Datum and template colours go through {@link resolveThemeColor}, same as
22
+ * per-series colours, so palette paths such as `'primary.main'` work.
23
+ */
24
+ export function createItemColorResolver({
25
+ theme,
26
+ datums,
27
+ template,
28
+ fallback,
29
+ }: {
30
+ theme: Theme
31
+ datums: readonly unknown[]
32
+ template: unknown
33
+ fallback: ItemColorCallback
34
+ }): ItemColorCallback {
35
+ const templateColor = (template as { itemStyle?: { color?: unknown } })
36
+ ?.itemStyle?.color
37
+ return (params) => {
38
+ const datumColor = readColor(datums[params.dataIndex])
39
+ if (datumColor) return resolveThemeColor(theme, datumColor)!
40
+ const custom =
41
+ typeof templateColor === 'function'
42
+ ? (templateColor as (p: CallbackDataParams) => unknown)(params)
43
+ : templateColor
44
+ if (typeof custom === 'string' && custom !== '') {
45
+ return resolveThemeColor(theme, custom)!
46
+ }
47
+ return fallback(params)
48
+ }
49
+ }
50
+
51
+ function readColor(datum: unknown): string | undefined {
52
+ if (datum == null || typeof datum !== 'object') return undefined
53
+ const color = (datum as { color?: unknown }).color
54
+ return typeof color === 'string' && color !== '' ? color : undefined
55
+ }