@carto/ps-react-ui 6.0.0 → 6.1.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.
- package/dist/actions-BWlS5tpP.js +1150 -0
- package/dist/actions-BWlS5tpP.js.map +1 -0
- package/dist/category-alzjKzvQ.js +839 -0
- package/dist/category-alzjKzvQ.js.map +1 -0
- package/dist/{download-Vlzn2jzb.js → download-B4sykOFm.js} +94 -83
- package/dist/download-B4sykOFm.js.map +1 -0
- package/dist/{echart-DjcbtKgi.js → echart-CV8F50gn.js} +6 -5
- package/dist/echart-CV8F50gn.js.map +1 -0
- package/dist/{formula-CdHWtepq.js → formula-DJS-JLpk.js} +10 -16
- package/dist/{formula-CdHWtepq.js.map → formula-DJS-JLpk.js.map} +1 -1
- package/dist/legend.js +34 -21
- package/dist/legend.js.map +1 -1
- package/dist/{markdown-CY-67NRE.js → markdown-Bn2nKCbn.js} +12 -18
- package/dist/{markdown-CY-67NRE.js.map → markdown-Bn2nKCbn.js.map} +1 -1
- package/dist/{range-DHQSsl2_.js → range-BpU2zBmq.js} +2 -2
- package/dist/{range-DHQSsl2_.js.map → range-BpU2zBmq.js.map} +1 -1
- package/dist/{spread-DuM5oTI1.js → spread-CQwFIwuz.js} +10 -16
- package/dist/{spread-DuM5oTI1.js.map → spread-CQwFIwuz.js.map} +1 -1
- package/dist/{stores-B8CHbgw-.js → stores-DcBOZlU3.js} +30 -24
- package/dist/stores-DcBOZlU3.js.map +1 -0
- package/dist/{table-BE4uO9pp.js → table-DEdW_fDj.js} +7 -13
- package/dist/{table-BE4uO9pp.js.map → table-DEdW_fDj.js.map} +1 -1
- package/dist/types/legend/stores/types.d.ts +4 -2
- package/dist/types/widgets/actions/download/csv-item.d.ts +3 -3
- package/dist/types/widgets/actions/download/index.d.ts +2 -1
- package/dist/types/widgets/actions/download/png-item.d.ts +2 -2
- package/dist/types/widgets/actions/download/types.d.ts +12 -1
- package/dist/types/widgets/actions/download/widget-download.d.ts +26 -0
- package/dist/types/widgets/actions/fullscreen/fullscreen.d.ts +20 -13
- package/dist/types/widgets/actions/index.d.ts +1 -1
- package/dist/types/widgets/actions/searcher/filter.d.ts +3 -2
- package/dist/types/widgets/actions/searcher/searcher-toggle.d.ts +3 -0
- package/dist/types/widgets/bar/download.d.ts +6 -20
- package/dist/types/widgets/category/category-ui.d.ts +9 -1
- package/dist/types/widgets/category/download.d.ts +5 -10
- package/dist/types/widgets/category/helpers.d.ts +10 -0
- package/dist/types/widgets/echart/style.d.ts +1 -0
- package/dist/types/widgets/formula/download.d.ts +5 -15
- package/dist/types/widgets/histogram/download.d.ts +3 -8
- package/dist/types/widgets/index.d.ts +1 -1
- package/dist/types/widgets/markdown/download.d.ts +5 -11
- package/dist/types/widgets/pie/download.d.ts +3 -8
- package/dist/types/widgets/scatterplot/download.d.ts +6 -11
- package/dist/types/widgets/spread/download.d.ts +6 -12
- package/dist/types/widgets/stores/index.d.ts +1 -1
- package/dist/types/widgets/stores/widget-store-registry.d.ts +14 -0
- package/dist/types/widgets/table/download.d.ts +7 -13
- package/dist/types/widgets/timeseries/download.d.ts +7 -12
- package/dist/types/widgets/toolbox/toolbox.d.ts +1 -1
- package/dist/{utils-BStJWhZN.js → utils-C-eWwOhE.js} +2 -2
- package/dist/{utils-BStJWhZN.js.map → utils-C-eWwOhE.js.map} +1 -1
- package/dist/widgets/actions.js +4 -4
- package/dist/widgets/bar.js +11 -17
- package/dist/widgets/bar.js.map +1 -1
- package/dist/widgets/category.js +1 -1
- package/dist/widgets/echart.js +1 -1
- package/dist/widgets/formula.js +1 -1
- package/dist/widgets/histogram.js +14 -20
- package/dist/widgets/histogram.js.map +1 -1
- package/dist/widgets/markdown.js +1 -1
- package/dist/widgets/pie.js +13 -19
- package/dist/widgets/pie.js.map +1 -1
- package/dist/widgets/range.js +1 -1
- package/dist/widgets/scatterplot.js +13 -19
- package/dist/widgets/scatterplot.js.map +1 -1
- package/dist/widgets/spread.js +1 -1
- package/dist/widgets/stores.js +2 -2
- package/dist/widgets/table.js +1 -1
- package/dist/widgets/timeseries.js +16 -22
- package/dist/widgets/timeseries.js.map +1 -1
- package/dist/widgets/utils.js +1 -1
- package/dist/widgets.js +274 -333
- package/dist/widgets.js.map +1 -1
- package/dist/{zoom-toggle-D_VuA01l.js → zoom-toggle-MmLjMTEw.js} +2 -2
- package/dist/{zoom-toggle-D_VuA01l.js.map → zoom-toggle-MmLjMTEw.js.map} +1 -1
- package/package.json +1 -1
- package/src/legend/components/legend-item/legend-item-ui.test.tsx +22 -1
- package/src/legend/components/legend-ramp/legend-ramp-ui.tsx +22 -6
- package/src/legend/stores/types.ts +4 -2
- package/src/widgets/actions/download/csv-item.test.tsx +3 -3
- package/src/widgets/actions/download/csv-item.tsx +6 -6
- package/src/widgets/actions/download/download.tsx +5 -3
- package/src/widgets/actions/download/index.ts +2 -1
- package/src/widgets/actions/download/png-item.test.tsx +5 -3
- package/src/widgets/actions/download/png-item.tsx +4 -4
- package/src/widgets/actions/download/types.ts +15 -1
- package/src/widgets/actions/download/widget-download.test.ts +30 -0
- package/src/widgets/actions/download/widget-download.ts +41 -0
- package/src/widgets/actions/fullscreen/fullscreen-store.test.tsx +155 -0
- package/src/widgets/actions/fullscreen/fullscreen.test.tsx +39 -41
- package/src/widgets/actions/fullscreen/fullscreen.tsx +198 -96
- package/src/widgets/actions/index.ts +3 -0
- package/src/widgets/actions/searcher/filter.test.ts +28 -0
- package/src/widgets/actions/searcher/filter.ts +22 -4
- package/src/widgets/actions/searcher/searcher-toggle.tsx +16 -8
- package/src/widgets/actions/searcher/searcher.test.tsx +22 -0
- package/src/widgets/actions/searcher/searcher.tsx +17 -7
- package/src/widgets/bar/download.test.tsx +5 -3
- package/src/widgets/bar/download.tsx +11 -35
- package/src/widgets/category/category-ui.tsx +26 -14
- package/src/widgets/category/category.tsx +37 -2
- package/src/widgets/category/components/category-legend.tsx +1 -2
- package/src/widgets/category/download.test.ts +4 -2
- package/src/widgets/category/download.ts +14 -27
- package/src/widgets/category/helpers.test.ts +17 -0
- package/src/widgets/category/helpers.ts +16 -0
- package/src/widgets/echart/style.ts +6 -0
- package/src/widgets/formula/download.test.tsx +3 -1
- package/src/widgets/formula/download.tsx +10 -30
- package/src/widgets/histogram/download.test.ts +6 -4
- package/src/widgets/histogram/download.ts +13 -26
- package/src/widgets/index.ts +1 -0
- package/src/widgets/markdown/download.test.ts +2 -2
- package/src/widgets/markdown/download.tsx +11 -26
- package/src/widgets/pie/download.test.ts +7 -3
- package/src/widgets/pie/download.ts +12 -25
- package/src/widgets/scatterplot/download.test.ts +4 -2
- package/src/widgets/scatterplot/download.ts +15 -28
- package/src/widgets/spread/download.test.ts +3 -1
- package/src/widgets/spread/download.ts +13 -27
- package/src/widgets/stores/index.ts +2 -0
- package/src/widgets/stores/widget-store-registry.test.ts +25 -0
- package/src/widgets/stores/widget-store-registry.ts +22 -0
- package/src/widgets/table/download.test.ts +5 -3
- package/src/widgets/table/download.ts +15 -29
- package/src/widgets/timeseries/download.test.ts +6 -4
- package/src/widgets/timeseries/download.ts +16 -29
- package/src/widgets/toolbox/toolbox.tsx +1 -1
- package/dist/actions-KsX1xdDM.js +0 -1024
- package/dist/actions-KsX1xdDM.js.map +0 -1
- package/dist/category-CsdDqDzo.js +0 -833
- package/dist/category-CsdDqDzo.js.map +0 -1
- package/dist/download-Vlzn2jzb.js.map +0 -1
- package/dist/echart-DjcbtKgi.js.map +0 -1
- package/dist/stores-B8CHbgw-.js.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildCsvDownloadItem,
|
|
3
|
-
|
|
3
|
+
withPngItem,
|
|
4
4
|
type DownloadItem,
|
|
5
|
+
type WidgetDownloadArgs,
|
|
5
6
|
} from '../actions/download'
|
|
6
7
|
import type { PieWidgetData } from './types'
|
|
7
8
|
|
|
@@ -9,33 +10,20 @@ import type { PieWidgetData } from './types'
|
|
|
9
10
|
* Download menu items for the Pie widget. Always includes a CSV item with
|
|
10
11
|
* `series, name, value` columns (one row per slice; series labels come from
|
|
11
12
|
* `seriesNames` if provided, else `series_<n>`). When `getCaptureEl` is
|
|
12
|
-
*
|
|
13
|
+
* given, prepends a PNG item that rasterises the captured element via
|
|
13
14
|
* `html2canvas`.
|
|
14
15
|
*/
|
|
15
|
-
export function createPieDownloadConfig(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}): DownloadItem[] {
|
|
23
|
-
const items: DownloadItem[] = []
|
|
24
|
-
if (args.getCaptureEl) {
|
|
25
|
-
items.push(
|
|
26
|
-
buildPngDownloadItem({
|
|
27
|
-
filename: args.filename,
|
|
28
|
-
getCaptureEl: args.getCaptureEl,
|
|
29
|
-
pixelRatio: args.pngPixelRatio,
|
|
30
|
-
backgroundColor: args.pngBackgroundColor,
|
|
31
|
-
}),
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
items.push(
|
|
16
|
+
export function createPieDownloadConfig(
|
|
17
|
+
args: WidgetDownloadArgs<PieWidgetData> & {
|
|
18
|
+
seriesNames?: readonly string[]
|
|
19
|
+
},
|
|
20
|
+
): DownloadItem[] {
|
|
21
|
+
return withPngItem(
|
|
22
|
+
args,
|
|
35
23
|
buildCsvDownloadItem({
|
|
36
24
|
filename: args.filename,
|
|
37
|
-
getRows: () => {
|
|
38
|
-
const data = args.getData()
|
|
25
|
+
getRows: (ctx) => {
|
|
26
|
+
const data = args.getData(ctx)
|
|
39
27
|
const rows: unknown[][] = [['series', 'name', 'value']]
|
|
40
28
|
for (const [i, series] of data.entries()) {
|
|
41
29
|
const seriesName = args.seriesNames?.[i] ?? `series_${i + 1}`
|
|
@@ -47,5 +35,4 @@ export function createPieDownloadConfig(args: {
|
|
|
47
35
|
},
|
|
48
36
|
}),
|
|
49
37
|
)
|
|
50
|
-
return items
|
|
51
38
|
}
|
|
@@ -52,7 +52,9 @@ describe('createScatterplotDownloadConfig', () => {
|
|
|
52
52
|
filename: 's',
|
|
53
53
|
getData: () => data,
|
|
54
54
|
})
|
|
55
|
-
const handle = await items
|
|
55
|
+
const handle = await items
|
|
56
|
+
.find((i) => i.id === 'csv')!
|
|
57
|
+
.resolve({ id: null })
|
|
56
58
|
expect(handle.filename).toBe('s.csv')
|
|
57
59
|
expect(csvText).toBe(
|
|
58
60
|
'series,x,y\nseries_1,1,10\nseries_1,2,20\nseries_2,3,30',
|
|
@@ -65,7 +67,7 @@ describe('createScatterplotDownloadConfig', () => {
|
|
|
65
67
|
getData: () => data,
|
|
66
68
|
seriesNames: ['A', 'B'],
|
|
67
69
|
})
|
|
68
|
-
await items.find((i) => i.id === 'csv')!.resolve()
|
|
70
|
+
await items.find((i) => i.id === 'csv')!.resolve({ id: null })
|
|
69
71
|
expect(csvText.split('\n')[1]).toBe('A,1,10')
|
|
70
72
|
})
|
|
71
73
|
})
|
|
@@ -1,40 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildCsvDownloadItem,
|
|
3
|
-
|
|
3
|
+
withPngItem,
|
|
4
4
|
type DownloadItem,
|
|
5
|
+
type WidgetDownloadArgs,
|
|
5
6
|
} from '../actions/download'
|
|
6
7
|
import type { ScatterplotWidgetData } from './types'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Download menu items for the Scatterplot widget. Always includes a CSV
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Download menu items for the Scatterplot widget. Always includes a CSV item
|
|
11
|
+
* with `series, x, y` columns (one row per point). When `getCaptureEl` is
|
|
12
|
+
* given, prepends a PNG item that rasterises the captured element via
|
|
13
|
+
* `html2canvas`.
|
|
13
14
|
*/
|
|
14
|
-
export function createScatterplotDownloadConfig(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}): DownloadItem[] {
|
|
22
|
-
const items: DownloadItem[] = []
|
|
23
|
-
if (args.getCaptureEl) {
|
|
24
|
-
items.push(
|
|
25
|
-
buildPngDownloadItem({
|
|
26
|
-
filename: args.filename,
|
|
27
|
-
getCaptureEl: args.getCaptureEl,
|
|
28
|
-
pixelRatio: args.pngPixelRatio,
|
|
29
|
-
backgroundColor: args.pngBackgroundColor,
|
|
30
|
-
}),
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
items.push(
|
|
15
|
+
export function createScatterplotDownloadConfig(
|
|
16
|
+
args: WidgetDownloadArgs<ScatterplotWidgetData> & {
|
|
17
|
+
seriesNames?: readonly string[]
|
|
18
|
+
},
|
|
19
|
+
): DownloadItem[] {
|
|
20
|
+
return withPngItem(
|
|
21
|
+
args,
|
|
34
22
|
buildCsvDownloadItem({
|
|
35
23
|
filename: args.filename,
|
|
36
|
-
getRows: () => {
|
|
37
|
-
const data = args.getData()
|
|
24
|
+
getRows: (ctx) => {
|
|
25
|
+
const data = args.getData(ctx)
|
|
38
26
|
const rows: unknown[][] = [['series', 'x', 'y']]
|
|
39
27
|
for (const [i, series] of data.entries()) {
|
|
40
28
|
const seriesName = args.seriesNames?.[i] ?? `series_${i + 1}`
|
|
@@ -46,5 +34,4 @@ export function createScatterplotDownloadConfig(args: {
|
|
|
46
34
|
},
|
|
47
35
|
}),
|
|
48
36
|
)
|
|
49
|
-
return items
|
|
50
37
|
}
|
|
@@ -55,7 +55,9 @@ describe('createSpreadDownloadConfig', () => {
|
|
|
55
55
|
filename: 's',
|
|
56
56
|
getData: () => data,
|
|
57
57
|
})
|
|
58
|
-
const handle = await items
|
|
58
|
+
const handle = await items
|
|
59
|
+
.find((i) => i.id === 'csv')!
|
|
60
|
+
.resolve({ id: null })
|
|
59
61
|
expect(handle.filename).toBe('s.csv')
|
|
60
62
|
expect(csvText).toBe(
|
|
61
63
|
'series,prefix,min,max,suffix,note\nRevenue,$,1,9,k,q1\n,,0,10,,',
|
|
@@ -1,39 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildCsvDownloadItem,
|
|
3
|
-
|
|
3
|
+
withPngItem,
|
|
4
4
|
type DownloadItem,
|
|
5
|
+
type WidgetDownloadArgs,
|
|
5
6
|
} from '../actions/download'
|
|
6
7
|
import type { SpreadWidgetData } from './types'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Download menu items for the Spread widget. Always includes a CSV item
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Download menu items for the Spread widget. Always includes a CSV item with
|
|
11
|
+
* `series, prefix, min, max, suffix, note` columns (one row per entry). When
|
|
12
|
+
* `getCaptureEl` is given, prepends a PNG item that rasterises the captured
|
|
13
|
+
* element via `html2canvas`.
|
|
13
14
|
*/
|
|
14
|
-
export function createSpreadDownloadConfig(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
pngBackgroundColor?: string | null
|
|
20
|
-
}): DownloadItem[] {
|
|
21
|
-
const items: DownloadItem[] = []
|
|
22
|
-
if (args.getCaptureEl) {
|
|
23
|
-
items.push(
|
|
24
|
-
buildPngDownloadItem({
|
|
25
|
-
filename: args.filename,
|
|
26
|
-
getCaptureEl: args.getCaptureEl,
|
|
27
|
-
pixelRatio: args.pngPixelRatio,
|
|
28
|
-
backgroundColor: args.pngBackgroundColor,
|
|
29
|
-
}),
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
items.push(
|
|
15
|
+
export function createSpreadDownloadConfig(
|
|
16
|
+
args: WidgetDownloadArgs<SpreadWidgetData>,
|
|
17
|
+
): DownloadItem[] {
|
|
18
|
+
return withPngItem(
|
|
19
|
+
args,
|
|
33
20
|
buildCsvDownloadItem({
|
|
34
21
|
filename: args.filename,
|
|
35
|
-
getRows: () => {
|
|
36
|
-
const data = args.getData()
|
|
22
|
+
getRows: (ctx) => {
|
|
23
|
+
const data = args.getData(ctx)
|
|
37
24
|
const rows: unknown[][] = [
|
|
38
25
|
['series', 'prefix', 'min', 'max', 'suffix', 'note'],
|
|
39
26
|
]
|
|
@@ -51,5 +38,4 @@ export function createSpreadDownloadConfig(args: {
|
|
|
51
38
|
},
|
|
52
39
|
}),
|
|
53
40
|
)
|
|
54
|
-
return items
|
|
55
41
|
}
|
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
setEchartInstance,
|
|
21
21
|
subscribeEchartInstance,
|
|
22
22
|
unregisterWidgetStore,
|
|
23
|
+
widgetCaptureEl,
|
|
24
|
+
widgetStoreData,
|
|
23
25
|
} from './widget-store-registry'
|
|
24
26
|
import type { ECharts } from 'echarts'
|
|
25
27
|
|
|
@@ -290,3 +292,26 @@ describe('widget-store-registry', () => {
|
|
|
290
292
|
})
|
|
291
293
|
})
|
|
292
294
|
})
|
|
295
|
+
|
|
296
|
+
describe('download getters', () => {
|
|
297
|
+
beforeEach(() => clearAllWidgetStores())
|
|
298
|
+
afterEach(() => clearAllWidgetStores())
|
|
299
|
+
|
|
300
|
+
it('read the store the menu was opened from, else the given id', () => {
|
|
301
|
+
registerWidgetStore('card', createWidgetStore('card', { data: 'card' }))
|
|
302
|
+
registerWidgetStore('modal', createWidgetStore('modal', { data: 'modal' }))
|
|
303
|
+
const getData = widgetStoreData<string>('card')
|
|
304
|
+
expect(getData({ id: 'modal' })).toBe('modal')
|
|
305
|
+
expect(getData({ id: null })).toBe('card')
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
it('capture element: same rule', () => {
|
|
309
|
+
const card = document.createElement('div')
|
|
310
|
+
const modal = document.createElement('div')
|
|
311
|
+
setCaptureEl('card', card)
|
|
312
|
+
setCaptureEl('modal', modal)
|
|
313
|
+
const getEl = widgetCaptureEl('card')
|
|
314
|
+
expect(getEl({ id: 'modal' })).toBe(modal)
|
|
315
|
+
expect(getEl({ id: null })).toBe(card)
|
|
316
|
+
})
|
|
317
|
+
})
|
|
@@ -6,6 +6,7 @@ import { useShallow } from 'zustand/react/shallow'
|
|
|
6
6
|
import { isDev } from '@carto/ps-utils'
|
|
7
7
|
import { pipelineMiddleware } from './pipeline-middleware'
|
|
8
8
|
import type { WidgetInit, WidgetState, WidgetStoreApi } from './types'
|
|
9
|
+
import type { DownloadContext } from '../actions/download/types'
|
|
9
10
|
|
|
10
11
|
const widgetStores = new Map<string, WidgetStoreApi>()
|
|
11
12
|
|
|
@@ -86,6 +87,27 @@ export function getCaptureEl(id: string): HTMLElement | null {
|
|
|
86
87
|
return captureEls.get(id) ?? null
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
/**
|
|
91
|
+
* `getData` for a `create*DownloadConfig`: the `data` of the store the
|
|
92
|
+
* download menu was opened from (`ctx.id` — the fullscreen dialog's own
|
|
93
|
+
* while it's open), or of widget `id` when the menu sits outside a
|
|
94
|
+
* `<Widget.Provider>`.
|
|
95
|
+
*/
|
|
96
|
+
export function widgetStoreData<T>(id: string): (ctx: DownloadContext) => T {
|
|
97
|
+
return (ctx) => getWidgetStore(ctx.id ?? id).getState().data as T
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* `getCaptureEl` for a `create*DownloadConfig`: the capture element of the
|
|
102
|
+
* store the download menu was opened from (`ctx.id`), or of widget `id`
|
|
103
|
+
* outside a `<Widget.Provider>`.
|
|
104
|
+
*/
|
|
105
|
+
export function widgetCaptureEl(
|
|
106
|
+
id: string,
|
|
107
|
+
): (ctx: DownloadContext) => HTMLElement | null {
|
|
108
|
+
return (ctx) => getCaptureEl(ctx.id ?? id)
|
|
109
|
+
}
|
|
110
|
+
|
|
89
111
|
/** @internal — exposed for tests and debugging only. */
|
|
90
112
|
export function clearAllCaptureEls(): void {
|
|
91
113
|
captureEls.clear()
|
|
@@ -56,7 +56,9 @@ describe('createTableDownloadConfig', () => {
|
|
|
56
56
|
getData: () => data,
|
|
57
57
|
columns,
|
|
58
58
|
})
|
|
59
|
-
const handle = await items
|
|
59
|
+
const handle = await items
|
|
60
|
+
.find((i) => i.id === 'csv')!
|
|
61
|
+
.resolve({ id: null })
|
|
60
62
|
expect(handle.filename).toBe('t.csv')
|
|
61
63
|
expect(csvText).toBe('Name,Score\nAlpha,10\nBeta,20')
|
|
62
64
|
})
|
|
@@ -67,7 +69,7 @@ describe('createTableDownloadConfig', () => {
|
|
|
67
69
|
getData: () => [{ id: 1, name: '=HYPERLINK("x")', score: 1 }],
|
|
68
70
|
columns,
|
|
69
71
|
})
|
|
70
|
-
await items.find((i) => i.id === 'csv')!.resolve()
|
|
72
|
+
await items.find((i) => i.id === 'csv')!.resolve({ id: null })
|
|
71
73
|
expect(csvText).toBe('Name,Score\n"\'=HYPERLINK(""x"")",1')
|
|
72
74
|
})
|
|
73
75
|
|
|
@@ -79,7 +81,7 @@ describe('createTableDownloadConfig', () => {
|
|
|
79
81
|
columns,
|
|
80
82
|
})
|
|
81
83
|
snapshot = [{ id: 9, name: 'Gamma', score: 99 }]
|
|
82
|
-
await items.find((i) => i.id === 'csv')!.resolve()
|
|
84
|
+
await items.find((i) => i.id === 'csv')!.resolve({ id: null })
|
|
83
85
|
expect(csvText).toBe('Name,Score\nGamma,99')
|
|
84
86
|
})
|
|
85
87
|
})
|
|
@@ -1,43 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildCsvDownloadItem,
|
|
3
|
-
|
|
3
|
+
withPngItem,
|
|
4
4
|
type DownloadItem,
|
|
5
|
+
type WidgetDownloadArgs,
|
|
5
6
|
} from '../actions/download'
|
|
6
7
|
import { tableDataToCsv } from './helpers'
|
|
7
8
|
import type { TableColumn, TableWidgetData } from './types'
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
* Download menu items for the Table widget. Always includes a CSV item
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* `html2canvas`.
|
|
11
|
+
* Download menu items for the Table widget. Always includes a CSV item that
|
|
12
|
+
* pulls the latest data from the widget store via `getData()` (so locked /
|
|
13
|
+
* sorted / filtered state is honored); headers come from `column.label`,
|
|
14
|
+
* cells from `row[column.id]`. When `getCaptureEl` is given, prepends a PNG
|
|
15
|
+
* item that rasterises the captured element via `html2canvas`.
|
|
16
16
|
*/
|
|
17
|
-
export function createTableDownloadConfig(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}): DownloadItem[] {
|
|
25
|
-
const items: DownloadItem[] = []
|
|
26
|
-
if (opts.getCaptureEl) {
|
|
27
|
-
items.push(
|
|
28
|
-
buildPngDownloadItem({
|
|
29
|
-
filename: opts.filename,
|
|
30
|
-
getCaptureEl: opts.getCaptureEl,
|
|
31
|
-
pixelRatio: opts.pngPixelRatio,
|
|
32
|
-
backgroundColor: opts.pngBackgroundColor,
|
|
33
|
-
}),
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
items.push(
|
|
17
|
+
export function createTableDownloadConfig(
|
|
18
|
+
opts: WidgetDownloadArgs<TableWidgetData> & {
|
|
19
|
+
columns: readonly TableColumn[]
|
|
20
|
+
},
|
|
21
|
+
): DownloadItem[] {
|
|
22
|
+
return withPngItem(
|
|
23
|
+
opts,
|
|
37
24
|
buildCsvDownloadItem({
|
|
38
25
|
filename: opts.filename,
|
|
39
|
-
getCsv: () => tableDataToCsv(opts.getData(), opts.columns),
|
|
26
|
+
getCsv: (ctx) => tableDataToCsv(opts.getData(ctx), opts.columns),
|
|
40
27
|
}),
|
|
41
28
|
)
|
|
42
|
-
return items
|
|
43
29
|
}
|
|
@@ -53,7 +53,9 @@ describe('createTimeseriesDownloadConfig', () => {
|
|
|
53
53
|
filename: 't',
|
|
54
54
|
getData: () => data,
|
|
55
55
|
})
|
|
56
|
-
const handle = await items
|
|
56
|
+
const handle = await items
|
|
57
|
+
.find((i) => i.id === 'csv')!
|
|
58
|
+
.resolve({ id: null })
|
|
57
59
|
expect(handle.filename).toBe('t.csv')
|
|
58
60
|
expect(csvText).toBe(
|
|
59
61
|
'time,series_1,series_2\n' +
|
|
@@ -69,7 +71,7 @@ describe('createTimeseriesDownloadConfig', () => {
|
|
|
69
71
|
filename: 't',
|
|
70
72
|
getData: () => data,
|
|
71
73
|
})
|
|
72
|
-
await items.find((i) => i.id === 'csv')!.resolve()
|
|
74
|
+
await items.find((i) => i.id === 'csv')!.resolve({ id: null })
|
|
73
75
|
expect(csvText).toContain('2024-01-01T00:00:00.000Z,7')
|
|
74
76
|
})
|
|
75
77
|
|
|
@@ -79,7 +81,7 @@ describe('createTimeseriesDownloadConfig', () => {
|
|
|
79
81
|
filename: 't',
|
|
80
82
|
getData: () => data,
|
|
81
83
|
})
|
|
82
|
-
await items.find((i) => i.id === 'csv')!.resolve()
|
|
84
|
+
await items.find((i) => i.id === 'csv')!.resolve({ id: null })
|
|
83
85
|
expect(csvText).toContain('2024-Q1,1')
|
|
84
86
|
})
|
|
85
87
|
|
|
@@ -89,7 +91,7 @@ describe('createTimeseriesDownloadConfig', () => {
|
|
|
89
91
|
getData: () => [[{ name: '2024', value: 1 }]],
|
|
90
92
|
seriesNames: ['revenue'],
|
|
91
93
|
})
|
|
92
|
-
await items.find((i) => i.id === 'csv')!.resolve()
|
|
94
|
+
await items.find((i) => i.id === 'csv')!.resolve({ id: null })
|
|
93
95
|
expect(csvText.split('\n')[0]).toBe('time,revenue')
|
|
94
96
|
})
|
|
95
97
|
})
|
|
@@ -1,41 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildCsvDownloadItem,
|
|
3
|
-
|
|
3
|
+
withPngItem,
|
|
4
4
|
type DownloadItem,
|
|
5
|
+
type WidgetDownloadArgs,
|
|
5
6
|
} from '../actions/download'
|
|
6
7
|
import type { TimeseriesWidgetData } from './types'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Download menu items for the Timeseries widget. Always includes a CSV
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `getCaptureEl` is
|
|
13
|
-
*
|
|
10
|
+
* Download menu items for the Timeseries widget. Always includes a CSV item
|
|
11
|
+
* with `time, series_1, series_2, …` columns (one row per unique time across
|
|
12
|
+
* all series; ISO-8601 strings for `Date`/numeric times). When
|
|
13
|
+
* `getCaptureEl` is given, prepends a PNG item that rasterises the captured
|
|
14
|
+
* element via `html2canvas`.
|
|
14
15
|
*/
|
|
15
|
-
export function createTimeseriesDownloadConfig(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}): DownloadItem[] {
|
|
23
|
-
const items: DownloadItem[] = []
|
|
24
|
-
if (args.getCaptureEl) {
|
|
25
|
-
items.push(
|
|
26
|
-
buildPngDownloadItem({
|
|
27
|
-
filename: args.filename,
|
|
28
|
-
getCaptureEl: args.getCaptureEl,
|
|
29
|
-
pixelRatio: args.pngPixelRatio,
|
|
30
|
-
backgroundColor: args.pngBackgroundColor,
|
|
31
|
-
}),
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
items.push(
|
|
16
|
+
export function createTimeseriesDownloadConfig(
|
|
17
|
+
args: WidgetDownloadArgs<TimeseriesWidgetData> & {
|
|
18
|
+
seriesNames?: readonly string[]
|
|
19
|
+
},
|
|
20
|
+
): DownloadItem[] {
|
|
21
|
+
return withPngItem(
|
|
22
|
+
args,
|
|
35
23
|
buildCsvDownloadItem({
|
|
36
24
|
filename: args.filename,
|
|
37
|
-
getRows: () => {
|
|
38
|
-
const data = args.getData()
|
|
25
|
+
getRows: (ctx) => {
|
|
26
|
+
const data = args.getData(ctx)
|
|
39
27
|
const seriesCount = data.length
|
|
40
28
|
|
|
41
29
|
// Collect every unique time, preserving insertion order.
|
|
@@ -72,7 +60,6 @@ export function createTimeseriesDownloadConfig(args: {
|
|
|
72
60
|
},
|
|
73
61
|
}),
|
|
74
62
|
)
|
|
75
|
-
return items
|
|
76
63
|
}
|
|
77
64
|
|
|
78
65
|
function formatTime(v: Date | number | string): string {
|
|
@@ -56,7 +56,7 @@ export interface ToolboxProps {
|
|
|
56
56
|
* Smart overflow toolbar with **single-mount** items. Children mount once
|
|
57
57
|
* into a stable, hidden host element and are *physically reparented* via
|
|
58
58
|
* `appendChild` between the inline preview area and the overflow `<Paper>`
|
|
59
|
-
* as the popper opens / closes
|
|
59
|
+
* as the popper opens / closes.
|
|
60
60
|
* Items with no inline space when closed are kept mounted but visually
|
|
61
61
|
* hidden via `display: none`.
|
|
62
62
|
*
|