@carto/ps-react-ui 4.3.6 → 4.3.7
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.
- package/dist/components.js +123 -123
- package/dist/components.js.map +1 -1
- package/dist/error-CEkRPccv.js +39 -0
- package/dist/error-CEkRPccv.js.map +1 -0
- package/dist/{lasso-tool-BctzdzBu.js → lasso-tool-jl4YK02H.js} +19 -19
- package/dist/lasso-tool-jl4YK02H.js.map +1 -0
- package/dist/no-data-hR3KcJ-_.js +60 -0
- package/dist/no-data-hR3KcJ-_.js.map +1 -0
- package/dist/{row-D3uVFImu.js → row-BKmVAUN5.js} +2 -2
- package/dist/{row-D3uVFImu.js.map → row-BKmVAUN5.js.map} +1 -1
- package/dist/{series-BAImrSBo.js → series-D1pynfeh.js} +3 -3
- package/dist/{series-BAImrSBo.js.map → series-D1pynfeh.js.map} +1 -1
- package/dist/{styles-CCZnY17y.js → styles-DrPyd0y5.js} +28 -22
- package/dist/styles-DrPyd0y5.js.map +1 -0
- package/dist/types/components/lasso-tool/types.d.ts +1 -1
- package/dist/types/widgets/_shared/chart-config/index.d.ts +1 -1
- package/dist/types/widgets/_shared/chart-config/option-builders.d.ts +7 -0
- package/dist/types/widgets/_shared/chart-config/option-builders.test.d.ts +1 -0
- package/dist/types/widgets/actions/index.d.ts +2 -2
- package/dist/types/widgets/actions/lock-selection/types.d.ts +0 -13
- package/dist/types/widgets/actions/relative-data/types.d.ts +0 -4
- package/dist/types/widgets/actions/searcher/types.d.ts +0 -2
- package/dist/types/widgets/actions/stack-toggle/types.d.ts +0 -4
- package/dist/types/widgets/echart/types.d.ts +0 -4
- package/dist/types/widgets/echart/utils.d.ts +2 -1
- package/dist/types/widgets/error/error.d.ts +1 -1
- package/dist/types/widgets/error/types.d.ts +8 -0
- package/dist/types/widgets/loader/loader.d.ts +1 -1
- package/dist/types/widgets/loader/types.d.ts +1 -1
- package/dist/types/widgets/stores/types.d.ts +1 -1
- package/dist/{use-widget-ref-B8x4sHIj.js → use-widget-ref-P-2i0MJG.js} +2 -2
- package/dist/{use-widget-ref-B8x4sHIj.js.map → use-widget-ref-P-2i0MJG.js.map} +1 -1
- package/dist/{utils-D3-eQyDR.js → utils-idmvq0Oa.js} +17 -16
- package/dist/utils-idmvq0Oa.js.map +1 -0
- package/dist/{widget-store-Dn0Bnc4h.js → widget-store-CzDt8oSK.js} +31 -46
- package/dist/widget-store-CzDt8oSK.js.map +1 -0
- package/dist/widgets/actions.js +690 -716
- package/dist/widgets/actions.js.map +1 -1
- package/dist/widgets/bar.js +67 -63
- package/dist/widgets/bar.js.map +1 -1
- package/dist/widgets/category.js +250 -241
- package/dist/widgets/category.js.map +1 -1
- package/dist/widgets/echart.js +93 -100
- package/dist/widgets/echart.js.map +1 -1
- package/dist/widgets/error.js +1 -1
- package/dist/widgets/formula.js +64 -72
- package/dist/widgets/formula.js.map +1 -1
- package/dist/widgets/histogram.js +75 -73
- package/dist/widgets/histogram.js.map +1 -1
- package/dist/widgets/loader.js +1 -1
- package/dist/widgets/loader.js.map +1 -1
- package/dist/widgets/markdown.js +2 -2
- package/dist/widgets/no-data.js +1 -1
- package/dist/widgets/pie.js +4 -4
- package/dist/widgets/range.js +97 -105
- package/dist/widgets/range.js.map +1 -1
- package/dist/widgets/scatterplot.js +8 -8
- package/dist/widgets/skeleton-loader.js +1 -1
- package/dist/widgets/spread.js +84 -100
- package/dist/widgets/spread.js.map +1 -1
- package/dist/widgets/stores.js +1 -1
- package/dist/widgets/table.js +493 -485
- package/dist/widgets/table.js.map +1 -1
- package/dist/widgets/timeseries.js +4 -4
- package/dist/widgets/wrapper.js +156 -156
- package/dist/widgets/wrapper.js.map +1 -1
- package/dist/widgets.js +4 -4
- package/package.json +3 -3
- package/src/components/lasso-tool/lasso-tool-inline.tsx +19 -17
- package/src/components/lasso-tool/lasso-tool.tsx +22 -20
- package/src/components/lasso-tool/types.ts +4 -3
- package/src/widgets/_shared/chart-config/index.ts +1 -0
- package/src/widgets/_shared/chart-config/option-builders.test.ts +40 -0
- package/src/widgets/_shared/chart-config/option-builders.ts +12 -0
- package/src/widgets/actions/fullscreen/fullscreen.tsx +5 -8
- package/src/widgets/actions/index.ts +2 -5
- package/src/widgets/actions/lock-selection/lock-selection.test.tsx +28 -30
- package/src/widgets/actions/lock-selection/lock-selection.tsx +25 -26
- package/src/widgets/actions/lock-selection/types.ts +0 -17
- package/src/widgets/actions/relative-data/relative-data.test.tsx +13 -13
- package/src/widgets/actions/relative-data/relative-data.tsx +18 -21
- package/src/widgets/actions/relative-data/types.ts +0 -7
- package/src/widgets/actions/searcher/searcher.tsx +40 -22
- package/src/widgets/actions/searcher/types.ts +0 -2
- package/src/widgets/actions/stack-toggle/stack-toggle.test.tsx +19 -9
- package/src/widgets/actions/stack-toggle/stack-toggle.tsx +32 -22
- package/src/widgets/actions/stack-toggle/types.ts +0 -8
- package/src/widgets/actions/zoom-toggle/zoom-toggle.tsx +113 -95
- package/src/widgets/bar/config.ts +37 -28
- package/src/widgets/category/category-ui.tsx +25 -22
- package/src/widgets/echart/echart-ui.test.tsx +3 -18
- package/src/widgets/echart/echart-ui.tsx +4 -22
- package/src/widgets/echart/echart.test.tsx +9 -25
- package/src/widgets/echart/echart.tsx +36 -29
- package/src/widgets/echart/types.ts +0 -4
- package/src/widgets/echart/utils.ts +3 -1
- package/src/widgets/error/error.tsx +17 -14
- package/src/widgets/error/types.ts +10 -0
- package/src/widgets/formula/components/value.tsx +13 -13
- package/src/widgets/histogram/config.ts +36 -29
- package/src/widgets/loader/loader.tsx +3 -1
- package/src/widgets/loader/types.ts +3 -1
- package/src/widgets/no-data/no-data.tsx +8 -11
- package/src/widgets/range/components/range-item.tsx +9 -13
- package/src/widgets/spread/components/max-value.tsx +13 -13
- package/src/widgets/spread/components/min-value.tsx +13 -13
- package/src/widgets/stores/types.ts +1 -4
- package/src/widgets/stores/widget-store.ts +1 -27
- package/src/widgets/table/hooks/use-pagination.ts +44 -35
- package/src/widgets/table/hooks/use-sort.ts +25 -23
- package/src/widgets/wrapper/wrapper-ui.tsx +16 -17
- package/dist/error-piB8FwYO.js +0 -38
- package/dist/error-piB8FwYO.js.map +0 -1
- package/dist/lasso-tool-BctzdzBu.js.map +0 -1
- package/dist/no-data-jdlbMef0.js +0 -61
- package/dist/no-data-jdlbMef0.js.map +0 -1
- package/dist/styles-CCZnY17y.js.map +0 -1
- package/dist/utils-D3-eQyDR.js.map +0 -1
- package/dist/widget-store-Dn0Bnc4h.js.map +0 -1
|
@@ -3,13 +3,8 @@ import * as echarts from 'echarts'
|
|
|
3
3
|
import type { EchartUIProps } from './types'
|
|
4
4
|
import { useWidgetRef } from '../../hooks'
|
|
5
5
|
|
|
6
|
-
const DEFAULT_REPLACE_MERGE: string[] = ['dataset', 'series']
|
|
7
|
-
|
|
8
6
|
export function EchartUI(props: EchartUIProps) {
|
|
9
7
|
const { id, ref, init, option, className, style, onEvents } = props
|
|
10
|
-
const replaceMerge = toReplaceMerge(
|
|
11
|
-
(props as { replaceMerge?: unknown }).replaceMerge,
|
|
12
|
-
)
|
|
13
8
|
|
|
14
9
|
const chartRef = useWidgetRef<HTMLDivElement>(id)
|
|
15
10
|
const chartInstance = useRef<echarts.ECharts>(null)
|
|
@@ -34,16 +29,11 @@ export function EchartUI(props: EchartUIProps) {
|
|
|
34
29
|
|
|
35
30
|
// Update chart when options change
|
|
36
31
|
useEffect(() => {
|
|
37
|
-
|
|
32
|
+
chartInstance.current?.setOption(option, {
|
|
38
33
|
lazyUpdate: true,
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
chartInstance.current?.setOption(
|
|
43
|
-
option,
|
|
44
|
-
setOptionConfig as Parameters<echarts.ECharts['setOption']>[1],
|
|
45
|
-
)
|
|
46
|
-
}, [option, replaceMerge])
|
|
34
|
+
notMerge: true,
|
|
35
|
+
})
|
|
36
|
+
}, [option])
|
|
47
37
|
|
|
48
38
|
// Handle resize using ResizeObserver
|
|
49
39
|
useEffect(() => {
|
|
@@ -82,11 +72,3 @@ export function EchartUI(props: EchartUIProps) {
|
|
|
82
72
|
|
|
83
73
|
return <div id={id} ref={chartRef} style={style} className={className} />
|
|
84
74
|
}
|
|
85
|
-
|
|
86
|
-
function toReplaceMerge(value: unknown): string[] | undefined {
|
|
87
|
-
if (!Array.isArray(value)) {
|
|
88
|
-
return undefined
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return value.filter((item): item is string => typeof item === 'string')
|
|
92
|
-
}
|
|
@@ -184,7 +184,7 @@ describe('Echart', () => {
|
|
|
184
184
|
}),
|
|
185
185
|
{
|
|
186
186
|
lazyUpdate: true,
|
|
187
|
-
|
|
187
|
+
notMerge: true,
|
|
188
188
|
},
|
|
189
189
|
)
|
|
190
190
|
})
|
|
@@ -277,7 +277,7 @@ describe('Echart', () => {
|
|
|
277
277
|
|
|
278
278
|
expect(mockChart.setOption).toHaveBeenCalledWith(basicOption, {
|
|
279
279
|
lazyUpdate: true,
|
|
280
|
-
|
|
280
|
+
notMerge: true,
|
|
281
281
|
})
|
|
282
282
|
|
|
283
283
|
const newOption: EChartsOption = {
|
|
@@ -299,7 +299,7 @@ describe('Echart', () => {
|
|
|
299
299
|
|
|
300
300
|
expect(mockChart.setOption).toHaveBeenCalledWith(newOption, {
|
|
301
301
|
lazyUpdate: true,
|
|
302
|
-
|
|
302
|
+
notMerge: true,
|
|
303
303
|
})
|
|
304
304
|
})
|
|
305
305
|
|
|
@@ -367,7 +367,7 @@ describe('Echart', () => {
|
|
|
367
367
|
|
|
368
368
|
expect(mockChart.setOption).toHaveBeenCalledWith(complexOption, {
|
|
369
369
|
lazyUpdate: true,
|
|
370
|
-
|
|
370
|
+
notMerge: true,
|
|
371
371
|
})
|
|
372
372
|
})
|
|
373
373
|
|
|
@@ -404,7 +404,7 @@ describe('Echart', () => {
|
|
|
404
404
|
)
|
|
405
405
|
expect(mockChart.setOption).toHaveBeenCalledWith(basicOption, {
|
|
406
406
|
lazyUpdate: true,
|
|
407
|
-
|
|
407
|
+
notMerge: true,
|
|
408
408
|
})
|
|
409
409
|
expect(mockChart.on).toHaveBeenCalledWith('click', clickHandler)
|
|
410
410
|
})
|
|
@@ -447,7 +447,7 @@ describe('Echart', () => {
|
|
|
447
447
|
|
|
448
448
|
expect(mockChart.setOption).toHaveBeenCalledWith(emptyOption, {
|
|
449
449
|
lazyUpdate: true,
|
|
450
|
-
|
|
450
|
+
notMerge: true,
|
|
451
451
|
})
|
|
452
452
|
})
|
|
453
453
|
|
|
@@ -470,7 +470,7 @@ describe('Echart', () => {
|
|
|
470
470
|
}),
|
|
471
471
|
{
|
|
472
472
|
lazyUpdate: true,
|
|
473
|
-
|
|
473
|
+
notMerge: true,
|
|
474
474
|
},
|
|
475
475
|
)
|
|
476
476
|
})
|
|
@@ -516,7 +516,7 @@ describe('Echart', () => {
|
|
|
516
516
|
|
|
517
517
|
expect(mockChart.setOption).toHaveBeenCalledWith(basicOption, {
|
|
518
518
|
lazyUpdate: true,
|
|
519
|
-
|
|
519
|
+
notMerge: true,
|
|
520
520
|
})
|
|
521
521
|
|
|
522
522
|
rerender(<Echart id='chart-b' />)
|
|
@@ -525,27 +525,11 @@ describe('Echart', () => {
|
|
|
525
525
|
{ series: [{ type: 'line', data: [1, 2, 3] }] },
|
|
526
526
|
{
|
|
527
527
|
lazyUpdate: true,
|
|
528
|
-
|
|
528
|
+
notMerge: true,
|
|
529
529
|
},
|
|
530
530
|
)
|
|
531
531
|
})
|
|
532
532
|
|
|
533
|
-
test('passes replaceMerge from widget to EchartUI', () => {
|
|
534
|
-
useWidgetStore.getState().setWidget('test-echart', {
|
|
535
|
-
id: 'test-echart',
|
|
536
|
-
type: 'echart',
|
|
537
|
-
option: basicOption,
|
|
538
|
-
replaceMerge: ['series'],
|
|
539
|
-
} as EchartWidgetState)
|
|
540
|
-
|
|
541
|
-
render(<Echart id='test-echart' />)
|
|
542
|
-
|
|
543
|
-
expect(mockChart.setOption).toHaveBeenCalledWith(basicOption, {
|
|
544
|
-
lazyUpdate: true,
|
|
545
|
-
replaceMerge: ['series'],
|
|
546
|
-
})
|
|
547
|
-
})
|
|
548
|
-
|
|
549
533
|
test('disposes chart when component unmounts', () => {
|
|
550
534
|
useWidgetStore.getState().setWidget('test-echart', {
|
|
551
535
|
id: 'test-echart',
|
|
@@ -10,43 +10,50 @@ import { useShallow } from 'zustand/shallow'
|
|
|
10
10
|
import { useMemo } from 'react'
|
|
11
11
|
|
|
12
12
|
export function Echart(props: EchartProps) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
const id = useWidgetStore(
|
|
14
|
+
(state) => state.getWidget<EchartWidgetState>(props.id)?.id,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const data = useWidgetStore(
|
|
18
|
+
useShallow(
|
|
19
|
+
(state) =>
|
|
20
|
+
state.getWidget<EchartWidgetState>(props.id)?.data as
|
|
21
|
+
| EchartWidgetData
|
|
22
|
+
| undefined,
|
|
23
|
+
),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
const widgetOption = useWidgetStore(
|
|
27
|
+
useShallow((state) => state.getWidget<EchartWidgetState>(props.id)?.option),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const onEvents = useWidgetStore(
|
|
31
|
+
useShallow(
|
|
32
|
+
(state) => state.getWidget<EchartWidgetState>(props.id)?.onEvents,
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const init = useWidgetStore(
|
|
37
|
+
(state) => state.getWidget<EchartWidgetState>(props.id)?.init,
|
|
25
38
|
)
|
|
26
39
|
|
|
27
40
|
// Memoize dataset transformation to avoid re-computing on every render
|
|
28
|
-
const dataset = useMemo(() => buildDataset(
|
|
41
|
+
const dataset = useMemo(() => buildDataset(data), [data])
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
const option = useMemo<EchartOptionsProps>(
|
|
44
|
+
() => ({
|
|
45
|
+
...widgetOption,
|
|
46
|
+
...(dataset && { dataset }),
|
|
47
|
+
}),
|
|
48
|
+
[widgetOption, dataset],
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if (!id) {
|
|
31
52
|
return null
|
|
32
53
|
}
|
|
33
|
-
const option: EchartOptionsProps = {
|
|
34
|
-
...widget.option,
|
|
35
|
-
...(dataset && { dataset }),
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const onEvents = widget.onEvents
|
|
39
|
-
const init = widget.init
|
|
40
|
-
const replaceMerge = widget.replaceMerge
|
|
41
54
|
|
|
42
55
|
return (
|
|
43
|
-
<EchartUI
|
|
44
|
-
id={props.id}
|
|
45
|
-
option={option}
|
|
46
|
-
onEvents={onEvents}
|
|
47
|
-
init={init}
|
|
48
|
-
replaceMerge={replaceMerge}
|
|
49
|
-
/>
|
|
56
|
+
<EchartUI id={props.id} option={option} onEvents={onEvents} init={init} />
|
|
50
57
|
)
|
|
51
58
|
}
|
|
52
59
|
|
|
@@ -5,14 +5,12 @@ import type { Ref } from 'react'
|
|
|
5
5
|
import { theme as CartoTheme } from '@carto/meridian-ds/theme'
|
|
6
6
|
|
|
7
7
|
export type EchartOptionsProps = EChartsOption
|
|
8
|
-
export type EchartReplaceMerge = string[]
|
|
9
8
|
|
|
10
9
|
export interface EchartUIProps {
|
|
11
10
|
id: string
|
|
12
11
|
option: EchartOptionsProps
|
|
13
12
|
className?: string
|
|
14
13
|
init?: echarts.EChartsInitOpts
|
|
15
|
-
replaceMerge?: EchartReplaceMerge
|
|
16
14
|
style?: React.CSSProperties
|
|
17
15
|
ref?: Ref<echarts.ECharts>
|
|
18
16
|
onEvents?: Record<string, Parameters<echarts.ECharts['on']>[2]>
|
|
@@ -28,7 +26,6 @@ export type EchartWidgetState = BaseWidgetState<{
|
|
|
28
26
|
option: EchartUIProps['option']
|
|
29
27
|
onEvents?: EchartUIProps['onEvents']
|
|
30
28
|
init?: EchartUIProps['init']
|
|
31
|
-
replaceMerge?: EchartReplaceMerge
|
|
32
29
|
}>
|
|
33
30
|
|
|
34
31
|
export interface EchartWidgetOptionProps<D> {
|
|
@@ -41,5 +38,4 @@ export interface EchartWidgetProps {
|
|
|
41
38
|
type: string
|
|
42
39
|
option: EchartUIProps['option']
|
|
43
40
|
onEvents?: EchartUIProps['onEvents']
|
|
44
|
-
replaceMerge?: EchartReplaceMerge
|
|
45
41
|
}
|
|
@@ -35,12 +35,14 @@ export function getEChartZoomConfig(
|
|
|
35
35
|
ySlider = false,
|
|
36
36
|
showSliders = true,
|
|
37
37
|
xAxisLabelFormatter,
|
|
38
|
+
bottomOffset = 0,
|
|
38
39
|
} = {} as {
|
|
39
40
|
inside?: boolean
|
|
40
41
|
xSlider?: boolean
|
|
41
42
|
ySlider?: boolean
|
|
42
43
|
showSliders?: boolean
|
|
43
44
|
xAxisLabelFormatter?: (value: number) => string
|
|
45
|
+
bottomOffset?: number
|
|
44
46
|
},
|
|
45
47
|
theme?: Theme,
|
|
46
48
|
) {
|
|
@@ -72,7 +74,7 @@ export function getEChartZoomConfig(
|
|
|
72
74
|
throttle: 0,
|
|
73
75
|
type: 'slider',
|
|
74
76
|
xAxisIndex: [0],
|
|
75
|
-
bottom:
|
|
77
|
+
bottom: bottomOffset,
|
|
76
78
|
height: parseInt(theme?.spacing?.(4) ?? '32'),
|
|
77
79
|
show: zoom && showSliders,
|
|
78
80
|
zoomLock: !zoom,
|
|
@@ -3,28 +3,31 @@ import { useWidgetStore } from '../stores/widget-store'
|
|
|
3
3
|
import { useShallow } from 'zustand/shallow'
|
|
4
4
|
import type { WidgetErrorProps } from './types'
|
|
5
5
|
|
|
6
|
-
export function WidgetError({
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
}),
|
|
6
|
+
export function WidgetError({
|
|
7
|
+
id,
|
|
8
|
+
children,
|
|
9
|
+
title: titleProp,
|
|
10
|
+
description,
|
|
11
|
+
}: WidgetErrorProps) {
|
|
12
|
+
const isLoading = useWidgetStore(
|
|
13
|
+
useShallow((state) => state.widgets[id]?.isLoading),
|
|
16
14
|
)
|
|
15
|
+
const isFetching = useWidgetStore(
|
|
16
|
+
useShallow((state) => state.widgets[id]?.isFetching),
|
|
17
|
+
)
|
|
18
|
+
const error = useWidgetStore(useShallow((state) => state.widgets[id]?.error))
|
|
17
19
|
|
|
18
20
|
// Don't show error during loading/fetching states
|
|
19
|
-
if (
|
|
21
|
+
if (isLoading || isFetching) {
|
|
20
22
|
return children
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
// Show error UI if error exists
|
|
24
|
-
if (
|
|
25
|
-
const errorTitle =
|
|
26
|
+
if (error) {
|
|
27
|
+
const errorTitle = titleProp ?? error.title ?? 'Error'
|
|
26
28
|
const errorMessage =
|
|
27
|
-
|
|
29
|
+
description ??
|
|
30
|
+
error.message ??
|
|
28
31
|
'An error occurred while loading the widget. Please try again.'
|
|
29
32
|
|
|
30
33
|
return (
|
|
@@ -11,4 +11,14 @@ export interface WidgetErrorProps {
|
|
|
11
11
|
* Children to render when no error exists
|
|
12
12
|
*/
|
|
13
13
|
children: ReactNode
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Override error title
|
|
17
|
+
*/
|
|
18
|
+
title?: string
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Override error description/message
|
|
22
|
+
*/
|
|
23
|
+
description?: string
|
|
14
24
|
}
|
|
@@ -6,20 +6,20 @@ import { useShallow } from 'zustand/shallow'
|
|
|
6
6
|
const defaultFormatter = (value: number) => value.toString()
|
|
7
7
|
|
|
8
8
|
export function Value({ id, index = 0, ...props }: ValueProps) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} = useWidgetStore(
|
|
14
|
-
useShallow((state) => {
|
|
15
|
-
const widget = state.getWidget<FormulaWidgetState>(id)
|
|
16
|
-
return {
|
|
17
|
-
value: widget?.data?.[index]?.value,
|
|
18
|
-
color: widget?.data?.[index]?.color,
|
|
19
|
-
formatter: widget?.formatter,
|
|
20
|
-
}
|
|
21
|
-
}),
|
|
9
|
+
const value = useWidgetStore(
|
|
10
|
+
useShallow(
|
|
11
|
+
(state) => state.getWidget<FormulaWidgetState>(id)?.data?.[index]?.value,
|
|
12
|
+
),
|
|
22
13
|
)
|
|
14
|
+
const color = useWidgetStore(
|
|
15
|
+
useShallow(
|
|
16
|
+
(state) => state.getWidget<FormulaWidgetState>(id)?.data?.[index]?.color,
|
|
17
|
+
),
|
|
18
|
+
)
|
|
19
|
+
const formatter =
|
|
20
|
+
useWidgetStore(
|
|
21
|
+
useShallow((state) => state.getWidget<FormulaWidgetState>(id)?.formatter),
|
|
22
|
+
) ?? defaultFormatter
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<Item TypographyProps={{ color }} {...props}>
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
buildGridConfig,
|
|
15
15
|
createTooltipPositioner,
|
|
16
16
|
createTooltipFormatter,
|
|
17
|
-
|
|
17
|
+
niceNum,
|
|
18
18
|
} from '../_shared/chart-config'
|
|
19
19
|
import { downloadToCSV, downloadToPNG, type DownloadItem } from '../actions'
|
|
20
20
|
import type { ConfigProps } from '../loader/types'
|
|
@@ -49,33 +49,7 @@ function getOption({
|
|
|
49
49
|
}: HistogramConfig): EchartOptionsProps {
|
|
50
50
|
const hasLegend = (data?.length ?? 0) > 1
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
type: 'value' as const,
|
|
54
|
-
showMaxLabel: true,
|
|
55
|
-
showMinLabel: true,
|
|
56
|
-
splitNumber: 1,
|
|
57
|
-
axisLabel: {
|
|
58
|
-
fontSize: theme.typography.overlineDelicate.fontSize,
|
|
59
|
-
fontFamily: theme.typography.overlineDelicate.fontFamily,
|
|
60
|
-
margin: parseInt(theme.spacing(1)),
|
|
61
|
-
show: true,
|
|
62
|
-
showMaxLabel: true,
|
|
63
|
-
showMinLabel: true,
|
|
64
|
-
verticalAlign: 'bottom' as const,
|
|
65
|
-
},
|
|
66
|
-
axisLine: {
|
|
67
|
-
show: false,
|
|
68
|
-
},
|
|
69
|
-
axisTick: {
|
|
70
|
-
show: false,
|
|
71
|
-
},
|
|
72
|
-
splitLine: {
|
|
73
|
-
show: true,
|
|
74
|
-
lineStyle: {
|
|
75
|
-
color: theme.palette.black[4],
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
}
|
|
52
|
+
let niceMax = 1
|
|
79
53
|
|
|
80
54
|
return {
|
|
81
55
|
legend: buildLegendConfig(hasLegend),
|
|
@@ -110,7 +84,40 @@ function getOption({
|
|
|
110
84
|
},
|
|
111
85
|
},
|
|
112
86
|
},
|
|
113
|
-
yAxis:
|
|
87
|
+
yAxis: {
|
|
88
|
+
type: 'value' as const,
|
|
89
|
+
min: 0,
|
|
90
|
+
max: (extent: { min: number; max: number }) => {
|
|
91
|
+
niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)
|
|
92
|
+
return niceMax
|
|
93
|
+
},
|
|
94
|
+
splitNumber: 1,
|
|
95
|
+
axisLabel: {
|
|
96
|
+
fontSize: theme.typography.overlineDelicate.fontSize,
|
|
97
|
+
fontFamily: theme.typography.overlineDelicate.fontFamily,
|
|
98
|
+
margin: parseInt(theme.spacing(1)),
|
|
99
|
+
show: true,
|
|
100
|
+
showMaxLabel: true,
|
|
101
|
+
showMinLabel: true,
|
|
102
|
+
verticalAlign: 'bottom' as const,
|
|
103
|
+
formatter: (value: number) => {
|
|
104
|
+
if (value !== niceMax) return ''
|
|
105
|
+
return formatter ? formatter(value) : String(value)
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
axisLine: {
|
|
109
|
+
show: false,
|
|
110
|
+
},
|
|
111
|
+
axisTick: {
|
|
112
|
+
show: false,
|
|
113
|
+
},
|
|
114
|
+
splitLine: {
|
|
115
|
+
show: true,
|
|
116
|
+
lineStyle: {
|
|
117
|
+
color: theme.palette.black[4],
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
114
121
|
tooltip: {
|
|
115
122
|
position: createTooltipPositioner(theme),
|
|
116
123
|
formatter: createTooltipFormatter((item) => {
|
|
@@ -3,7 +3,9 @@ import type { WidgetLoaderProps } from './types'
|
|
|
3
3
|
import { useWidgetStore } from '../stores/widget-store'
|
|
4
4
|
import type { WrapperState } from '../wrapper'
|
|
5
5
|
|
|
6
|
-
export function WidgetLoader<T extends
|
|
6
|
+
export function WidgetLoader<T extends object = Record<string, unknown>>(
|
|
7
|
+
props: WidgetLoaderProps<T>,
|
|
8
|
+
) {
|
|
7
9
|
const setWidget = useWidgetStore((state) => state.setWidget)
|
|
8
10
|
const executeToolPipeline = useWidgetStore(
|
|
9
11
|
(state) => state.executeToolPipeline,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from 'react'
|
|
2
2
|
import type { WidgetsStoreProps, WidgetState } from '../stores/types'
|
|
3
3
|
|
|
4
|
-
export interface WidgetLoaderProps<
|
|
4
|
+
export interface WidgetLoaderProps<
|
|
5
|
+
T extends object = Record<string, unknown>,
|
|
6
|
+
> extends WidgetsStoreProps {
|
|
5
7
|
children: ReactNode
|
|
6
8
|
config?: T
|
|
7
9
|
}
|
|
@@ -45,25 +45,22 @@ export function WidgetNoData({
|
|
|
45
45
|
isEmpty = defaultIsEmpty,
|
|
46
46
|
}: WidgetNoDataProps) {
|
|
47
47
|
// Subscribe to widget store with selective subscription for optimal performance
|
|
48
|
-
const
|
|
49
|
-
useShallow((state) =>
|
|
50
|
-
const w = state.widgets[id]
|
|
51
|
-
return {
|
|
52
|
-
isLoading: w?.isLoading,
|
|
53
|
-
isFetching: w?.isFetching,
|
|
54
|
-
data: w?.data,
|
|
55
|
-
}
|
|
56
|
-
}),
|
|
48
|
+
const isLoading = useWidgetStore(
|
|
49
|
+
useShallow((state) => state.widgets[id]?.isLoading),
|
|
57
50
|
)
|
|
51
|
+
const isFetching = useWidgetStore(
|
|
52
|
+
useShallow((state) => state.widgets[id]?.isFetching),
|
|
53
|
+
)
|
|
54
|
+
const data = useWidgetStore(useShallow((state) => state.widgets[id]?.data))
|
|
58
55
|
|
|
59
56
|
// If loading or fetching, show children
|
|
60
57
|
// SkeletonLoader handles loading state, this allows proper composition
|
|
61
|
-
if (
|
|
58
|
+
if (isLoading || isFetching) {
|
|
62
59
|
return children
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
// Check if data is empty
|
|
66
|
-
if (isEmpty(
|
|
63
|
+
if (isEmpty(data)) {
|
|
67
64
|
return (
|
|
68
65
|
<Box sx={styles.root}>
|
|
69
66
|
<Typography variant='body2' color='text.primary'>
|
|
@@ -10,20 +10,16 @@ type EditingState = '' | 'min' | 'max'
|
|
|
10
10
|
const defaultFormatter = (value: number) => value.toString()
|
|
11
11
|
|
|
12
12
|
export function RangeItem({ id, index }: RangeItemProps) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
useShallow((state) => {
|
|
19
|
-
const widget = state.getWidget<RangeWidgetState>(id)
|
|
20
|
-
return {
|
|
21
|
-
item: widget?.data[index],
|
|
22
|
-
onChange: widget?.onChange,
|
|
23
|
-
formatter: widget?.formatter,
|
|
24
|
-
}
|
|
25
|
-
}),
|
|
13
|
+
const item = useWidgetStore(
|
|
14
|
+
useShallow((state) => state.getWidget<RangeWidgetState>(id)?.data[index]),
|
|
15
|
+
)
|
|
16
|
+
const onChange = useWidgetStore(
|
|
17
|
+
useShallow((state) => state.getWidget<RangeWidgetState>(id)?.onChange),
|
|
26
18
|
)
|
|
19
|
+
const formatter =
|
|
20
|
+
useWidgetStore(
|
|
21
|
+
useShallow((state) => state.getWidget<RangeWidgetState>(id)?.formatter),
|
|
22
|
+
) ?? defaultFormatter
|
|
27
23
|
const getWidget = useWidgetStore((store) => store.getWidget)
|
|
28
24
|
const setWidget = useWidgetStore((store) => store.setWidget)
|
|
29
25
|
|
|
@@ -6,20 +6,20 @@ import { useShallow } from 'zustand/shallow'
|
|
|
6
6
|
const defaultFormatter = (value: number) => value.toString()
|
|
7
7
|
|
|
8
8
|
export function MaxValue({ id, index = 0, ...props }: ValueProps) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} = useWidgetStore(
|
|
14
|
-
useShallow((state) => {
|
|
15
|
-
const widget = state.getWidget<SpreadWidgetState>(id)
|
|
16
|
-
return {
|
|
17
|
-
max: widget?.data[index]?.max,
|
|
18
|
-
color: widget?.data[index]?.color,
|
|
19
|
-
formatter: widget?.formatter,
|
|
20
|
-
}
|
|
21
|
-
}),
|
|
9
|
+
const max = useWidgetStore(
|
|
10
|
+
useShallow(
|
|
11
|
+
(state) => state.getWidget<SpreadWidgetState>(id)?.data[index]?.max,
|
|
12
|
+
),
|
|
22
13
|
)
|
|
14
|
+
const color = useWidgetStore(
|
|
15
|
+
useShallow(
|
|
16
|
+
(state) => state.getWidget<SpreadWidgetState>(id)?.data[index]?.color,
|
|
17
|
+
),
|
|
18
|
+
)
|
|
19
|
+
const formatter =
|
|
20
|
+
useWidgetStore(
|
|
21
|
+
useShallow((state) => state.getWidget<SpreadWidgetState>(id)?.formatter),
|
|
22
|
+
) ?? defaultFormatter
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<Item TypographyProps={{ color }} {...props}>
|
|
@@ -6,20 +6,20 @@ import { useShallow } from 'zustand/shallow'
|
|
|
6
6
|
const defaultFormatter = (value: number) => value.toString()
|
|
7
7
|
|
|
8
8
|
export function MinValue({ id, index = 0, ...props }: ValueProps) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} = useWidgetStore(
|
|
14
|
-
useShallow((state) => {
|
|
15
|
-
const widget = state.getWidget<SpreadWidgetState>(id)
|
|
16
|
-
return {
|
|
17
|
-
min: widget?.data[index]?.min,
|
|
18
|
-
color: widget?.data[index]?.color,
|
|
19
|
-
formatter: widget?.formatter,
|
|
20
|
-
}
|
|
21
|
-
}),
|
|
9
|
+
const min = useWidgetStore(
|
|
10
|
+
useShallow(
|
|
11
|
+
(state) => state.getWidget<SpreadWidgetState>(id)?.data[index]?.min,
|
|
12
|
+
),
|
|
22
13
|
)
|
|
14
|
+
const color = useWidgetStore(
|
|
15
|
+
useShallow(
|
|
16
|
+
(state) => state.getWidget<SpreadWidgetState>(id)?.data[index]?.color,
|
|
17
|
+
),
|
|
18
|
+
)
|
|
19
|
+
const formatter =
|
|
20
|
+
useWidgetStore(
|
|
21
|
+
useShallow((state) => state.getWidget<SpreadWidgetState>(id)?.formatter),
|
|
22
|
+
) ?? defaultFormatter
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<Item TypographyProps={{ color }} {...props}>
|
|
@@ -200,10 +200,7 @@ export interface WidgetStoreActions {
|
|
|
200
200
|
* @param widgetId - Widget ID
|
|
201
201
|
* @param baseConfig - Base config to transform
|
|
202
202
|
*/
|
|
203
|
-
executeConfigPipeline: (
|
|
204
|
-
widgetId: string,
|
|
205
|
-
baseConfig: Record<string, unknown>,
|
|
206
|
-
) => Promise<void>
|
|
203
|
+
executeConfigPipeline: (widgetId: string, baseConfig: object) => Promise<void>
|
|
207
204
|
}
|
|
208
205
|
|
|
209
206
|
/**
|
|
@@ -243,10 +243,7 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
|
|
|
243
243
|
}
|
|
244
244
|
},
|
|
245
245
|
|
|
246
|
-
executeConfigPipeline: async (
|
|
247
|
-
widgetId: string,
|
|
248
|
-
baseConfig: Record<string, unknown>,
|
|
249
|
-
) => {
|
|
246
|
+
executeConfigPipeline: async (widgetId: string, baseConfig: object) => {
|
|
250
247
|
const widget = get().widgets[widgetId]
|
|
251
248
|
if (!widget) return
|
|
252
249
|
|
|
@@ -272,29 +269,6 @@ export const useWidgetStore = create<WidgetStore>()((set, get) => ({
|
|
|
272
269
|
)
|
|
273
270
|
.sort((a, b) => a.order - b.order)
|
|
274
271
|
|
|
275
|
-
// If no config tools, just set the base config directly
|
|
276
|
-
if (sortedTools.length === 0) {
|
|
277
|
-
set((state) => {
|
|
278
|
-
const currentWidget = state.widgets[widgetId]
|
|
279
|
-
if (!currentWidget) return state
|
|
280
|
-
|
|
281
|
-
return {
|
|
282
|
-
widgets: {
|
|
283
|
-
...state.widgets,
|
|
284
|
-
[widgetId]: {
|
|
285
|
-
...currentWidget,
|
|
286
|
-
...baseConfig,
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
}
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
if (activeConfigPipelines.get(widgetId) === currentExecution) {
|
|
293
|
-
activeConfigPipelines.delete(widgetId)
|
|
294
|
-
}
|
|
295
|
-
return
|
|
296
|
-
}
|
|
297
|
-
|
|
298
272
|
// Chain config tools
|
|
299
273
|
let transformedConfig: unknown = baseConfig
|
|
300
274
|
for (const tool of sortedTools) {
|