@carto/ps-react-ui 4.3.5 → 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-wFqOD6wk.js → lasso-tool-jl4YK02H.js} +184 -159
- 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-DrHwXNvF.js → row-BKmVAUN5.js} +2 -2
- package/dist/{row-DrHwXNvF.js.map → row-BKmVAUN5.js.map} +1 -1
- package/dist/{series-D3Pc-kYX.js → series-D1pynfeh.js} +3 -3
- package/dist/{series-D3Pc-kYX.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 +4 -4
- 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/stack-toggle.d.ts +3 -2
- package/dist/types/widgets/actions/stack-toggle/types.d.ts +0 -4
- package/dist/types/widgets/actions/zoom-toggle/zoom-toggle.d.ts +4 -0
- 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/index.d.ts +1 -1
- package/dist/types/widgets/stores/types.d.ts +15 -0
- package/dist/{use-widget-ref-B0aNCANx.js → use-widget-ref-P-2i0MJG.js} +2 -2
- package/dist/{use-widget-ref-B0aNCANx.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-CzDt8oSK.js +163 -0
- package/dist/widget-store-CzDt8oSK.js.map +1 -0
- package/dist/widgets/actions.js +714 -659
- 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 +41 -40
- 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 +27 -22
- 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 +4 -7
- 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 +160 -16
- package/src/widgets/actions/stack-toggle/stack-toggle.tsx +79 -78
- package/src/widgets/actions/stack-toggle/types.ts +0 -8
- package/src/widgets/actions/zoom-toggle/zoom-toggle.tsx +137 -87
- 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 +20 -8
- 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/index.ts +1 -0
- package/src/widgets/stores/types.ts +17 -0
- package/src/widgets/stores/widget-store.test.ts +141 -0
- package/src/widgets/stores/widget-store.ts +73 -2
- 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-B2IJ9d2h.js +0 -38
- package/dist/error-B2IJ9d2h.js.map +0 -1
- package/dist/lasso-tool-wFqOD6wk.js.map +0 -1
- package/dist/no-data-C54XJt13.js +0 -61
- package/dist/no-data-C54XJt13.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-CB6Trp_0.js +0 -131
- package/dist/widget-store-CB6Trp_0.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, test, expect, beforeEach } from 'vitest'
|
|
2
2
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
3
|
-
import { StackToggle } from './stack-toggle'
|
|
3
|
+
import { StackToggle, STACK_TOGGLE_TOOL_ID } from './stack-toggle'
|
|
4
4
|
import { useWidgetStore } from '../../stores/widget-store'
|
|
5
5
|
import { DEFAULT_STACK_GROUP } from '../../echart/const'
|
|
6
6
|
|
|
@@ -39,14 +39,17 @@ describe('StackToggle', () => {
|
|
|
39
39
|
expect(button).toBeTruthy()
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
test('toggles to stacked mode and updates
|
|
42
|
+
test('toggles to stacked mode and updates tool config', () => {
|
|
43
43
|
render(<StackToggle id={widgetId} />)
|
|
44
44
|
|
|
45
45
|
const button = screen.getByRole('button')
|
|
46
46
|
fireEvent.click(button)
|
|
47
47
|
|
|
48
48
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
49
|
-
|
|
49
|
+
const tool = widget?.registeredTools?.find(
|
|
50
|
+
(t) => t.id === STACK_TOGGLE_TOOL_ID,
|
|
51
|
+
)
|
|
52
|
+
expect(tool?.config?.stacked).toBe(true)
|
|
50
53
|
})
|
|
51
54
|
|
|
52
55
|
test('toggles back to unstacked mode', () => {
|
|
@@ -61,7 +64,10 @@ describe('StackToggle', () => {
|
|
|
61
64
|
fireEvent.click(button)
|
|
62
65
|
|
|
63
66
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
64
|
-
|
|
67
|
+
const tool = widget?.registeredTools?.find(
|
|
68
|
+
(t) => t.id === STACK_TOGGLE_TOOL_ID,
|
|
69
|
+
)
|
|
70
|
+
expect(tool?.config?.stacked).toBe(false)
|
|
65
71
|
})
|
|
66
72
|
|
|
67
73
|
test('has active state when in stacked mode', () => {
|
|
@@ -99,33 +105,48 @@ describe('StackToggle', () => {
|
|
|
99
105
|
expect(button).toBeTruthy()
|
|
100
106
|
})
|
|
101
107
|
|
|
102
|
-
test('initializes
|
|
108
|
+
test('initializes tool config with default values on mount', () => {
|
|
103
109
|
render(<StackToggle id={widgetId} />)
|
|
104
110
|
|
|
105
111
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
106
|
-
|
|
112
|
+
const tool = widget?.registeredTools?.find(
|
|
113
|
+
(t) => t.id === STACK_TOGGLE_TOOL_ID,
|
|
114
|
+
)
|
|
115
|
+
expect(tool?.config?.stacked).toBe(false)
|
|
107
116
|
})
|
|
108
117
|
|
|
109
|
-
test('initializes
|
|
118
|
+
test('initializes tool config with stacked values when defaultIsStacked is true', () => {
|
|
110
119
|
render(<StackToggle id={widgetId} defaultIsStacked />)
|
|
111
120
|
|
|
112
121
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
113
|
-
|
|
122
|
+
const tool = widget?.registeredTools?.find(
|
|
123
|
+
(t) => t.id === STACK_TOGGLE_TOOL_ID,
|
|
124
|
+
)
|
|
125
|
+
expect(tool?.config?.stacked).toBe(true)
|
|
114
126
|
})
|
|
115
127
|
|
|
116
|
-
test('
|
|
117
|
-
// setupMultiSeriesWidget already ran in beforeEach
|
|
128
|
+
test('applies stack to EChart series via config pipeline when toggling to stacked', async () => {
|
|
118
129
|
render(<StackToggle id={widgetId} />)
|
|
119
130
|
const button = screen.getByRole('button')
|
|
120
131
|
fireEvent.click(button)
|
|
121
132
|
|
|
133
|
+
// Run the config pipeline to apply the stack tool's transformation
|
|
134
|
+
await useWidgetStore.getState().executeConfigPipeline(widgetId, {
|
|
135
|
+
option: {
|
|
136
|
+
series: [
|
|
137
|
+
{ name: 'Series 1', type: 'bar' },
|
|
138
|
+
{ name: 'Series 2', type: 'bar' },
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
|
|
122
143
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
123
144
|
const series = (widget as { option?: { series?: { stack?: string }[] } })
|
|
124
145
|
?.option?.series?.[0]
|
|
125
146
|
expect(series?.stack).toBe(DEFAULT_STACK_GROUP)
|
|
126
147
|
})
|
|
127
148
|
|
|
128
|
-
test('removes stack from EChart series when toggling to unstacked', () => {
|
|
149
|
+
test('removes stack from EChart series via config pipeline when toggling to unstacked', async () => {
|
|
129
150
|
useWidgetStore.getState().setWidget(widgetId, {
|
|
130
151
|
option: {
|
|
131
152
|
series: [
|
|
@@ -141,13 +162,23 @@ describe('StackToggle', () => {
|
|
|
141
162
|
// First click unstacks (since series has stack, it starts stacked)
|
|
142
163
|
fireEvent.click(button)
|
|
143
164
|
|
|
165
|
+
// Run the config pipeline — tool is disabled when unstacked, so stack is removed
|
|
166
|
+
await useWidgetStore.getState().executeConfigPipeline(widgetId, {
|
|
167
|
+
option: {
|
|
168
|
+
series: [
|
|
169
|
+
{ name: 'Series 1', type: 'bar' },
|
|
170
|
+
{ name: 'Series 2', type: 'bar' },
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
})
|
|
174
|
+
|
|
144
175
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
145
176
|
const series = (widget as { option?: { series?: { stack?: string }[] } })
|
|
146
177
|
?.option?.series?.[0]
|
|
147
178
|
expect(series?.stack).toBeUndefined()
|
|
148
179
|
})
|
|
149
180
|
|
|
150
|
-
test('
|
|
181
|
+
test('applies stack to multiple series via config pipeline', async () => {
|
|
151
182
|
useWidgetStore.getState().setWidget(widgetId, {
|
|
152
183
|
option: {
|
|
153
184
|
series: [
|
|
@@ -162,6 +193,16 @@ describe('StackToggle', () => {
|
|
|
162
193
|
const button = screen.getByRole('button')
|
|
163
194
|
fireEvent.click(button)
|
|
164
195
|
|
|
196
|
+
await useWidgetStore.getState().executeConfigPipeline(widgetId, {
|
|
197
|
+
option: {
|
|
198
|
+
series: [
|
|
199
|
+
{ name: 'Series 1', type: 'bar' },
|
|
200
|
+
{ name: 'Series 2', type: 'bar' },
|
|
201
|
+
{ name: 'Series 3', type: 'bar' },
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
})
|
|
205
|
+
|
|
165
206
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
166
207
|
const seriesArray = (
|
|
167
208
|
widget as { option?: { series?: { stack?: string }[] } }
|
|
@@ -173,7 +214,7 @@ describe('StackToggle', () => {
|
|
|
173
214
|
})
|
|
174
215
|
})
|
|
175
216
|
|
|
176
|
-
test('
|
|
217
|
+
test('preserves custom stack group via config pipeline', async () => {
|
|
177
218
|
const customStackGroup = 'custom-group'
|
|
178
219
|
useWidgetStore.getState().setWidget(widgetId, {
|
|
179
220
|
option: {
|
|
@@ -187,11 +228,20 @@ describe('StackToggle', () => {
|
|
|
187
228
|
render(<StackToggle id={widgetId} />)
|
|
188
229
|
const button = screen.getByRole('button')
|
|
189
230
|
|
|
190
|
-
// Toggle off then on
|
|
231
|
+
// Toggle off then on
|
|
191
232
|
fireEvent.click(button) // unstacked
|
|
192
233
|
fireEvent.click(button) // stacked again
|
|
193
234
|
|
|
194
|
-
|
|
235
|
+
await useWidgetStore.getState().executeConfigPipeline(widgetId, {
|
|
236
|
+
option: {
|
|
237
|
+
series: [
|
|
238
|
+
{ name: 'Series 1', type: 'bar', stack: customStackGroup },
|
|
239
|
+
{ name: 'Series 2', type: 'bar', stack: customStackGroup },
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
await waitFor(() => {
|
|
195
245
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
196
246
|
const series = (widget as { option?: { series?: { stack?: string }[] } })
|
|
197
247
|
?.option?.series?.[0]
|
|
@@ -238,7 +288,73 @@ describe('StackToggle', () => {
|
|
|
238
288
|
expect(container.firstChild).toBeNull()
|
|
239
289
|
})
|
|
240
290
|
|
|
241
|
-
test('
|
|
291
|
+
test('config tool re-applies stack when config pipeline re-runs', async () => {
|
|
292
|
+
// Start with stacked widget
|
|
293
|
+
useWidgetStore.getState().setWidget(widgetId, {
|
|
294
|
+
option: {
|
|
295
|
+
series: [
|
|
296
|
+
{ name: 'Series 1', type: 'bar', stack: DEFAULT_STACK_GROUP },
|
|
297
|
+
{ name: 'Series 2', type: 'bar', stack: DEFAULT_STACK_GROUP },
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
render(<StackToggle id={widgetId} defaultIsStacked />)
|
|
303
|
+
|
|
304
|
+
// Simulate loader running config pipeline with base config (no stack)
|
|
305
|
+
await useWidgetStore.getState().executeConfigPipeline(widgetId, {
|
|
306
|
+
option: {
|
|
307
|
+
series: [
|
|
308
|
+
{ name: 'Series 1', type: 'bar' },
|
|
309
|
+
{ name: 'Series 2', type: 'bar' },
|
|
310
|
+
],
|
|
311
|
+
},
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
// Stack should be re-applied by the config tool
|
|
315
|
+
await waitFor(() => {
|
|
316
|
+
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
317
|
+
const series = (widget as { option?: { series?: { stack?: string }[] } })
|
|
318
|
+
?.option?.series
|
|
319
|
+
expect(series?.[0]?.stack).toBe(DEFAULT_STACK_GROUP)
|
|
320
|
+
expect(series?.[1]?.stack).toBe(DEFAULT_STACK_GROUP)
|
|
321
|
+
})
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
test('config tool does not apply stack when unstacked and pipeline re-runs', async () => {
|
|
325
|
+
// Start with unstacked widget
|
|
326
|
+
useWidgetStore.getState().setWidget(widgetId, {
|
|
327
|
+
option: {
|
|
328
|
+
series: [
|
|
329
|
+
{ name: 'Series 1', type: 'bar' },
|
|
330
|
+
{ name: 'Series 2', type: 'bar' },
|
|
331
|
+
],
|
|
332
|
+
},
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
render(<StackToggle id={widgetId} />)
|
|
336
|
+
|
|
337
|
+
// Run config pipeline with base config
|
|
338
|
+
await useWidgetStore.getState().executeConfigPipeline(widgetId, {
|
|
339
|
+
option: {
|
|
340
|
+
series: [
|
|
341
|
+
{ name: 'Series 1', type: 'bar' },
|
|
342
|
+
{ name: 'Series 2', type: 'bar' },
|
|
343
|
+
],
|
|
344
|
+
},
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
// Stack should NOT be applied since isStacked is false (tool disabled)
|
|
348
|
+
await waitFor(() => {
|
|
349
|
+
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
350
|
+
const series = (widget as { option?: { series?: { stack?: string }[] } })
|
|
351
|
+
?.option?.series
|
|
352
|
+
expect(series?.[0]?.stack).toBeUndefined()
|
|
353
|
+
expect(series?.[1]?.stack).toBeUndefined()
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
test('preserves other option properties via config pipeline', async () => {
|
|
242
358
|
useWidgetStore.getState().setWidget(widgetId, {
|
|
243
359
|
option: {
|
|
244
360
|
title: { text: 'My Chart' },
|
|
@@ -254,6 +370,17 @@ describe('StackToggle', () => {
|
|
|
254
370
|
const button = screen.getByRole('button')
|
|
255
371
|
fireEvent.click(button)
|
|
256
372
|
|
|
373
|
+
await useWidgetStore.getState().executeConfigPipeline(widgetId, {
|
|
374
|
+
option: {
|
|
375
|
+
title: { text: 'My Chart' },
|
|
376
|
+
xAxis: { type: 'category' },
|
|
377
|
+
series: [
|
|
378
|
+
{ name: 'Series 1', type: 'bar' },
|
|
379
|
+
{ name: 'Series 2', type: 'bar' },
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
})
|
|
383
|
+
|
|
257
384
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
258
385
|
const option = (
|
|
259
386
|
widget as {
|
|
@@ -267,4 +394,21 @@ describe('StackToggle', () => {
|
|
|
267
394
|
expect(option?.title?.text).toBe('My Chart')
|
|
268
395
|
expect(option?.xAxis?.type).toBe('category')
|
|
269
396
|
})
|
|
397
|
+
|
|
398
|
+
test('registers config tool on mount and unregisters on unmount', () => {
|
|
399
|
+
const { unmount } = render(<StackToggle id={widgetId} />)
|
|
400
|
+
|
|
401
|
+
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
402
|
+
const tools = widget?.registeredTools ?? []
|
|
403
|
+
const stackTool = tools.find((t) => t.id === STACK_TOGGLE_TOOL_ID)
|
|
404
|
+
expect(stackTool).toBeDefined()
|
|
405
|
+
expect(stackTool?.type).toBe('config')
|
|
406
|
+
|
|
407
|
+
unmount()
|
|
408
|
+
|
|
409
|
+
const widgetAfter = useWidgetStore.getState().getWidget(widgetId)
|
|
410
|
+
const toolsAfter = widgetAfter?.registeredTools ?? []
|
|
411
|
+
const stackToolAfter = toolsAfter.find((t) => t.id === STACK_TOGGLE_TOOL_ID)
|
|
412
|
+
expect(stackToolAfter).toBeUndefined()
|
|
413
|
+
})
|
|
270
414
|
})
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { IconButton } from '@mui/material'
|
|
2
2
|
import { useCallback, useEffect, useMemo } from 'react'
|
|
3
3
|
import { useWidgetStore } from '../../stores/widget-store'
|
|
4
|
-
import type { StackToggleProps
|
|
4
|
+
import type { StackToggleProps } from './types'
|
|
5
5
|
import { actionButtonStyles } from '../shared/styles'
|
|
6
6
|
import { Tooltip } from '../../../components'
|
|
7
7
|
import { GroupedBarChartIcon } from './grouped-bar-chart-icon'
|
|
8
8
|
import { getEChartStackConfig } from '../../echart/utils'
|
|
9
9
|
import { DEFAULT_STACK_GROUP } from '../../echart/const'
|
|
10
10
|
import type { EchartWidgetState } from '../../echart/types'
|
|
11
|
+
import type { EchartOptionsProps } from '../../echart/types'
|
|
11
12
|
import { useShallow } from 'zustand/shallow'
|
|
12
13
|
|
|
14
|
+
export const STACK_TOGGLE_TOOL_ID = 'stack-toggle'
|
|
15
|
+
|
|
13
16
|
/**
|
|
14
17
|
* Widget action to toggle stacking behavior in ECharts bar and histogram widgets.
|
|
15
18
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
19
|
+
* Registers as a config pipeline tool so that stack configuration is automatically
|
|
20
|
+
* re-applied when the base config is updated (e.g., by WidgetLoader).
|
|
18
21
|
*
|
|
19
22
|
* @example
|
|
20
23
|
* ```tsx
|
|
@@ -31,94 +34,92 @@ export function StackToggle({
|
|
|
31
34
|
Icon,
|
|
32
35
|
IconButtonProps,
|
|
33
36
|
}: StackToggleProps) {
|
|
34
|
-
const setWidget = useWidgetStore((state) => state.setWidget)
|
|
35
|
-
const storeIsStacked = useWidgetStore(
|
|
36
|
-
useShallow((state) => state.getWidget<StackToggleState>(id)?.isStacked),
|
|
37
|
-
)
|
|
38
|
-
|
|
39
37
|
const getWidget = useWidgetStore((state) => state.getWidget)
|
|
38
|
+
const registerTool = useWidgetStore((state) => state.registerTool)
|
|
39
|
+
const unregisterTool = useWidgetStore((state) => state.unregisterTool)
|
|
40
|
+
const setToolEnabled = useWidgetStore((state) => state.setToolEnabled)
|
|
41
|
+
const updateToolConfig = useWidgetStore((state) => state.updateToolConfig)
|
|
42
|
+
|
|
43
|
+
const stackTool = useWidgetStore(
|
|
44
|
+
useShallow((state) => {
|
|
45
|
+
const tools = state.getWidget(id)?.registeredTools ?? []
|
|
46
|
+
return tools.find((tool) => tool.id === STACK_TOGGLE_TOOL_ID)
|
|
47
|
+
}),
|
|
48
|
+
)
|
|
40
49
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const hasMultiSeries = useMemo(() => {
|
|
45
|
-
const option = getWidget<EchartWidgetState>(id)?.option
|
|
46
|
-
if (!option) return false
|
|
47
|
-
|
|
48
|
-
const series = Array.isArray(option.series)
|
|
49
|
-
? option.series
|
|
50
|
-
: [option.series]
|
|
51
|
-
|
|
52
|
-
return series.length > 1
|
|
53
|
-
}, [getWidget, id])
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Checks if any series in the option has a stack property defined
|
|
57
|
-
*/
|
|
58
|
-
const hasStackInSeries = useMemo(() => {
|
|
59
|
-
const option = getWidget<EchartWidgetState>(id)?.option
|
|
60
|
-
if (!option) return false
|
|
50
|
+
const option = useWidgetStore(
|
|
51
|
+
useShallow((state) => state.getWidget<EchartWidgetState>(id)?.option),
|
|
52
|
+
)
|
|
61
53
|
|
|
54
|
+
const { hasMultiSeries, hasStackInSeries } = useMemo(() => {
|
|
55
|
+
if (!option) return { hasMultiSeries: false, hasStackInSeries: false }
|
|
62
56
|
const series = Array.isArray(option.series)
|
|
63
57
|
? option.series
|
|
64
58
|
: [option.series]
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
return {
|
|
60
|
+
hasMultiSeries: series.length > 1,
|
|
61
|
+
hasStackInSeries: series.some((s) => (s as { stack?: string })?.stack),
|
|
62
|
+
}
|
|
63
|
+
}, [option])
|
|
68
64
|
|
|
69
65
|
// If series already has stack defined, default to stacked=true
|
|
70
66
|
const effectiveDefaultIsStacked = hasStackInSeries || defaultIsStacked
|
|
71
|
-
const isStacked =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
* Updates the ECharts option with the stack configuration
|
|
75
|
-
* Preserves existing stack group names from series, falling back to DEFAULT_STACK_GROUP
|
|
76
|
-
*/
|
|
77
|
-
const updateOptions = useCallback(
|
|
78
|
-
(stacked: boolean) => {
|
|
79
|
-
const option = getWidget<EchartWidgetState>(id)?.option
|
|
80
|
-
|
|
81
|
-
if (!option) return
|
|
82
|
-
|
|
83
|
-
const series = Array.isArray(option.series)
|
|
84
|
-
? option.series
|
|
85
|
-
: [option.series]
|
|
67
|
+
const isStacked =
|
|
68
|
+
(stackTool?.config?.stacked as boolean | undefined) ??
|
|
69
|
+
effectiveDefaultIsStacked
|
|
86
70
|
|
|
87
|
-
|
|
88
|
-
// Extract existing stack group from series, fallback to default
|
|
89
|
-
const existingStack = (s as { stack?: string })?.stack
|
|
90
|
-
const stackGroup =
|
|
91
|
-
typeof existingStack === 'string'
|
|
92
|
-
? existingStack
|
|
93
|
-
: DEFAULT_STACK_GROUP
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
...s,
|
|
97
|
-
...getEChartStackConfig(stacked, stackGroup),
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
setWidget(id, {
|
|
102
|
-
option: {
|
|
103
|
-
...option,
|
|
104
|
-
series: updatedSeries,
|
|
105
|
-
},
|
|
106
|
-
})
|
|
107
|
-
},
|
|
108
|
-
[getWidget, id, setWidget],
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
// Initialize store with default value only if not already configured
|
|
71
|
+
// Register config tool on mount
|
|
112
72
|
useEffect(() => {
|
|
113
|
-
|
|
114
|
-
|
|
73
|
+
const existingTool = getWidget(id)?.registeredTools?.find(
|
|
74
|
+
(tool) => tool.id === STACK_TOGGLE_TOOL_ID,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
const initialStacked =
|
|
78
|
+
(existingTool?.config?.stacked as boolean | undefined) ??
|
|
79
|
+
effectiveDefaultIsStacked
|
|
80
|
+
|
|
81
|
+
registerTool(id, {
|
|
82
|
+
id: STACK_TOGGLE_TOOL_ID,
|
|
83
|
+
type: 'config',
|
|
84
|
+
order: 10,
|
|
85
|
+
enabled: initialStacked && hasMultiSeries,
|
|
86
|
+
fn: (currentConfig, toolConfig) => {
|
|
87
|
+
const config = currentConfig as Record<string, unknown>
|
|
88
|
+
const option = config.option as EchartOptionsProps | undefined
|
|
89
|
+
if (!option) return currentConfig
|
|
90
|
+
|
|
91
|
+
const stacked = (toolConfig?.stacked as boolean) ?? false
|
|
92
|
+
const series = Array.isArray(option.series)
|
|
93
|
+
? option.series
|
|
94
|
+
: [option.series]
|
|
95
|
+
const updatedSeries = series.map((s) => {
|
|
96
|
+
const existingStack = (s as { stack?: string })?.stack
|
|
97
|
+
const stackGroup =
|
|
98
|
+
typeof existingStack === 'string'
|
|
99
|
+
? existingStack
|
|
100
|
+
: DEFAULT_STACK_GROUP
|
|
101
|
+
return { ...s, ...getEChartStackConfig(stacked, stackGroup) }
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
return { ...config, option: { ...option, series: updatedSeries } }
|
|
105
|
+
},
|
|
106
|
+
config: { stacked: initialStacked },
|
|
107
|
+
})
|
|
108
|
+
return () => unregisterTool(id, STACK_TOGGLE_TOOL_ID)
|
|
109
|
+
}, [
|
|
110
|
+
id,
|
|
111
|
+
registerTool,
|
|
112
|
+
unregisterTool,
|
|
113
|
+
effectiveDefaultIsStacked,
|
|
114
|
+
hasMultiSeries,
|
|
115
|
+
getWidget,
|
|
116
|
+
])
|
|
115
117
|
|
|
116
118
|
const handleToggle = useCallback(() => {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}, [isStacked, id, setWidget, updateOptions])
|
|
119
|
+
const newStacked = !isStacked
|
|
120
|
+
setToolEnabled(id, STACK_TOGGLE_TOOL_ID, newStacked && hasMultiSeries)
|
|
121
|
+
updateToolConfig(id, STACK_TOGGLE_TOOL_ID, { stacked: newStacked })
|
|
122
|
+
}, [isStacked, hasMultiSeries, id, setToolEnabled, updateToolConfig])
|
|
122
123
|
|
|
123
124
|
const tooltipLabel = isStacked
|
|
124
125
|
? (labels?.unstacked ?? 'Disable stacking')
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { IconButtonProps } from '@mui/material'
|
|
2
2
|
import type { ReactNode } from 'react'
|
|
3
|
-
import type { BaseWidgetState } from '../../stores/types'
|
|
4
|
-
|
|
5
3
|
export interface StackToggleProps {
|
|
6
4
|
/** Widget ID to update stack configuration in the widget store */
|
|
7
5
|
id: string
|
|
@@ -21,9 +19,3 @@ export interface StackToggleProps {
|
|
|
21
19
|
/** Custom icon to display */
|
|
22
20
|
Icon?: ReactNode
|
|
23
21
|
}
|
|
24
|
-
|
|
25
|
-
export type StackToggleState<T = unknown> = BaseWidgetState<
|
|
26
|
-
T & {
|
|
27
|
-
isStacked?: boolean
|
|
28
|
-
}
|
|
29
|
-
>
|