@carto/ps-react-ui 4.7.1 → 4.8.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/category-DwaeYjpX.js +656 -0
- package/dist/category-DwaeYjpX.js.map +1 -0
- package/dist/change-column-Cidl_M-4.js +1110 -0
- package/dist/change-column-Cidl_M-4.js.map +1 -0
- package/dist/data-zoom-layout-BH0LPwSy.js +28 -0
- package/dist/data-zoom-layout-BH0LPwSy.js.map +1 -0
- package/dist/echart-CU0KmClP.js +176 -0
- package/dist/echart-CU0KmClP.js.map +1 -0
- package/dist/exports-Cx-f6m6U.js +63 -0
- package/dist/exports-Cx-f6m6U.js.map +1 -0
- package/dist/formula-DuC0NQLH.js +79 -0
- package/dist/formula-DuC0NQLH.js.map +1 -0
- package/dist/markdown-BD1jcknS.js +8326 -0
- package/dist/markdown-BD1jcknS.js.map +1 -0
- package/dist/merge-options-DCkkHZIf.js +34 -0
- package/dist/merge-options-DCkkHZIf.js.map +1 -0
- package/dist/{styles-BYTyKQFP.js → option-builders-F-c9ELi1.js} +25 -45
- package/dist/option-builders-F-c9ELi1.js.map +1 -0
- package/dist/png-item-CS4z1iSH.js +45 -0
- package/dist/png-item-CS4z1iSH.js.map +1 -0
- package/dist/range-DsqTjSpg.js +186 -0
- package/dist/range-DsqTjSpg.js.map +1 -0
- package/dist/spread-CTuIXZSM.js +67 -0
- package/dist/spread-CTuIXZSM.js.map +1 -0
- package/dist/style-DVnT6HC1.js +131 -0
- package/dist/style-DVnT6HC1.js.map +1 -0
- package/dist/styles-cohnxh9F.js +23 -0
- package/dist/styles-cohnxh9F.js.map +1 -0
- package/dist/table-HIpXuq4G.js +390 -0
- package/dist/table-HIpXuq4G.js.map +1 -0
- package/dist/transforms-Cdx4fkU5.js +106 -0
- package/dist/transforms-Cdx4fkU5.js.map +1 -0
- package/dist/types/widgets/echart/utils.test.d.ts +1 -0
- package/dist/types/widgets/formula/config.test.d.ts +1 -0
- package/dist/types/widgets/stores/widget-store-branches.test.d.ts +1 -0
- package/dist/types/widgets/table/config.test.d.ts +1 -0
- package/dist/types/widgets-v2/actions/brush-toggle/brush-toggle.d.ts +56 -0
- package/dist/types/widgets-v2/actions/brush-toggle/index.d.ts +3 -0
- package/dist/types/widgets-v2/actions/brush-toggle/labels.d.ts +5 -0
- package/dist/types/widgets-v2/actions/brush-toggle/style.d.ts +12 -0
- package/dist/types/widgets-v2/actions/brush-toggle/transforms.d.ts +11 -0
- package/dist/types/widgets-v2/actions/brush-toggle/transforms.test.d.ts +1 -0
- package/dist/types/widgets-v2/actions/change-column/change-column-icon.d.ts +2 -0
- package/dist/types/widgets-v2/actions/change-column/change-column.d.ts +29 -0
- package/dist/types/widgets-v2/actions/change-column/index.d.ts +3 -0
- package/dist/types/widgets-v2/actions/change-column/labels.d.ts +5 -0
- package/dist/types/widgets-v2/actions/change-column/sortable-column-item.d.ts +14 -0
- package/dist/types/widgets-v2/actions/change-column/style.d.ts +33 -0
- package/dist/types/widgets-v2/actions/change-column/types.d.ts +10 -0
- package/dist/types/widgets-v2/actions/download/download.d.ts +18 -0
- package/dist/types/widgets-v2/actions/download/exports.d.ts +37 -0
- package/dist/types/widgets-v2/actions/download/icons.d.ts +12 -0
- package/dist/types/widgets-v2/actions/download/index.d.ts +6 -0
- package/dist/types/widgets-v2/actions/download/labels.d.ts +11 -0
- package/dist/types/widgets-v2/actions/download/png-item.d.ts +24 -0
- package/dist/types/widgets-v2/actions/download/style.d.ts +1 -0
- package/dist/types/widgets-v2/actions/download/types.d.ts +35 -0
- package/dist/types/widgets-v2/actions/fullscreen/fullscreen.d.ts +59 -0
- package/dist/types/widgets-v2/actions/fullscreen/index.d.ts +3 -0
- package/dist/types/widgets-v2/actions/fullscreen/labels.d.ts +5 -0
- package/dist/types/widgets-v2/actions/fullscreen/style.d.ts +48 -0
- package/dist/types/widgets-v2/actions/fullscreen/types.d.ts +14 -0
- package/dist/types/widgets-v2/actions/index.d.ts +9 -0
- package/dist/types/widgets-v2/actions/lock-selection/index.d.ts +3 -0
- package/dist/types/widgets-v2/actions/lock-selection/labels.d.ts +6 -0
- package/dist/types/widgets-v2/actions/lock-selection/lock-selection.d.ts +36 -0
- package/dist/types/widgets-v2/actions/lock-selection/style.d.ts +12 -0
- package/dist/types/widgets-v2/actions/lock-selection/transforms.d.ts +6 -0
- package/dist/types/widgets-v2/actions/relative-data/index.d.ts +3 -0
- package/dist/types/widgets-v2/actions/relative-data/labels.d.ts +5 -0
- package/dist/types/widgets-v2/actions/relative-data/relative-data.d.ts +39 -0
- package/dist/types/widgets-v2/actions/relative-data/style.d.ts +12 -0
- package/dist/types/widgets-v2/actions/relative-data/transforms.d.ts +30 -0
- package/dist/types/widgets-v2/actions/relative-data/transforms.test.d.ts +1 -0
- package/dist/types/widgets-v2/actions/searcher/filter.d.ts +6 -0
- package/dist/types/widgets-v2/actions/searcher/index.d.ts +4 -0
- package/dist/types/widgets-v2/actions/searcher/labels.d.ts +7 -0
- package/dist/types/widgets-v2/actions/searcher/searcher-toggle.d.ts +23 -0
- package/dist/types/widgets-v2/actions/searcher/searcher.d.ts +11 -0
- package/dist/types/widgets-v2/actions/searcher/style.d.ts +16 -0
- package/dist/types/widgets-v2/actions/stack-toggle/index.d.ts +3 -0
- package/dist/types/widgets-v2/actions/stack-toggle/labels.d.ts +5 -0
- package/dist/types/widgets-v2/actions/stack-toggle/stack-toggle.d.ts +10 -0
- package/dist/types/widgets-v2/actions/stack-toggle/style.d.ts +12 -0
- package/dist/types/widgets-v2/actions/stack-toggle/transforms.d.ts +13 -0
- package/dist/types/widgets-v2/actions/stack-toggle/transforms.test.d.ts +1 -0
- package/dist/types/widgets-v2/actions/zoom-toggle/index.d.ts +3 -0
- package/dist/types/widgets-v2/actions/zoom-toggle/labels.d.ts +5 -0
- package/dist/types/widgets-v2/actions/zoom-toggle/style.d.ts +12 -0
- package/dist/types/widgets-v2/actions/zoom-toggle/transforms.d.ts +51 -0
- package/dist/types/widgets-v2/actions/zoom-toggle/transforms.test.d.ts +1 -0
- package/dist/types/widgets-v2/actions/zoom-toggle/zoom-toggle.d.ts +35 -0
- package/dist/types/widgets-v2/bar/download.d.ts +24 -0
- package/dist/types/widgets-v2/bar/index.d.ts +4 -0
- package/dist/types/widgets-v2/bar/options.d.ts +43 -0
- package/dist/types/widgets-v2/bar/options.test.d.ts +1 -0
- package/dist/types/widgets-v2/bar/skeleton.d.ts +6 -0
- package/dist/types/widgets-v2/bar/types.d.ts +41 -0
- package/dist/types/widgets-v2/category/category-ui.d.ts +81 -0
- package/dist/types/widgets-v2/category/category.d.ts +48 -0
- package/dist/types/widgets-v2/category/components/category-bar-stacked.d.ts +28 -0
- package/dist/types/widgets-v2/category/components/category-bar.d.ts +23 -0
- package/dist/types/widgets-v2/category/components/category-legend.d.ts +18 -0
- package/dist/types/widgets-v2/category/components/category-row-multi.d.ts +31 -0
- package/dist/types/widgets-v2/category/components/category-row-other.d.ts +13 -0
- package/dist/types/widgets-v2/category/components/category-row-single.d.ts +28 -0
- package/dist/types/widgets-v2/category/components/category-row-stacked.d.ts +38 -0
- package/dist/types/widgets-v2/category/download.d.ts +16 -0
- package/dist/types/widgets-v2/category/download.test.d.ts +1 -0
- package/dist/types/widgets-v2/category/index.d.ts +10 -0
- package/dist/types/widgets-v2/category/skeleton.d.ts +11 -0
- package/dist/types/widgets-v2/category/style.d.ts +166 -0
- package/dist/types/widgets-v2/category/types.d.ts +49 -0
- package/dist/types/widgets-v2/echart/echart-ui.d.ts +44 -0
- package/dist/types/widgets-v2/echart/echart.d.ts +75 -0
- package/dist/types/widgets-v2/echart/index.d.ts +4 -0
- package/dist/types/widgets-v2/echart/shared-resize-observer.d.ts +5 -0
- package/dist/types/widgets-v2/echart/shared-resize-observer.test.d.ts +1 -0
- package/dist/types/widgets-v2/echart/style.d.ts +6 -0
- package/dist/types/widgets-v2/echart/use-chart-selection.d.ts +51 -0
- package/dist/types/widgets-v2/formula/delta.d.ts +22 -0
- package/dist/types/widgets-v2/formula/download.d.ts +20 -0
- package/dist/types/widgets-v2/formula/formula-ui.d.ts +20 -0
- package/dist/types/widgets-v2/formula/formula.d.ts +8 -0
- package/dist/types/widgets-v2/formula/index.d.ts +11 -0
- package/dist/types/widgets-v2/formula/note.d.ts +11 -0
- package/dist/types/widgets-v2/formula/prefix.d.ts +12 -0
- package/dist/types/widgets-v2/formula/series.d.ts +16 -0
- package/dist/types/widgets-v2/formula/skeleton.d.ts +4 -0
- package/dist/types/widgets-v2/formula/style.d.ts +29 -0
- package/dist/types/widgets-v2/formula/suffix.d.ts +12 -0
- package/dist/types/widgets-v2/formula/types.d.ts +40 -0
- package/dist/types/widgets-v2/formula/value.d.ts +14 -0
- package/dist/types/widgets-v2/histogram/download.d.ts +17 -0
- package/dist/types/widgets-v2/histogram/download.test.d.ts +1 -0
- package/dist/types/widgets-v2/histogram/index.d.ts +5 -0
- package/dist/types/widgets-v2/histogram/options.d.ts +42 -0
- package/dist/types/widgets-v2/histogram/options.test.d.ts +1 -0
- package/dist/types/widgets-v2/histogram/skeleton.d.ts +9 -0
- package/dist/types/widgets-v2/histogram/transforms.d.ts +17 -0
- package/dist/types/widgets-v2/histogram/transforms.test.d.ts +1 -0
- package/dist/types/widgets-v2/histogram/types.d.ts +47 -0
- package/dist/types/widgets-v2/index.d.ts +107 -0
- package/dist/types/widgets-v2/markdown/download.d.ts +16 -0
- package/dist/types/widgets-v2/markdown/download.test.d.ts +1 -0
- package/dist/types/widgets-v2/markdown/index.d.ts +6 -0
- package/dist/types/widgets-v2/markdown/markdown-content.d.ts +34 -0
- package/dist/types/widgets-v2/markdown/markdown-ui.d.ts +12 -0
- package/dist/types/widgets-v2/markdown/markdown.d.ts +6 -0
- package/dist/types/widgets-v2/markdown/skeleton.d.ts +4 -0
- package/dist/types/widgets-v2/markdown/style.d.ts +61 -0
- package/dist/types/widgets-v2/markdown/types.d.ts +4 -0
- package/dist/types/widgets-v2/note/labels.d.ts +5 -0
- package/dist/types/widgets-v2/note/style.d.ts +26 -0
- package/dist/types/widgets-v2/note/widget-note.d.ts +46 -0
- package/dist/types/widgets-v2/pie/download.d.ts +17 -0
- package/dist/types/widgets-v2/pie/download.test.d.ts +1 -0
- package/dist/types/widgets-v2/pie/index.d.ts +4 -0
- package/dist/types/widgets-v2/pie/options.d.ts +35 -0
- package/dist/types/widgets-v2/pie/options.test.d.ts +1 -0
- package/dist/types/widgets-v2/pie/skeleton.d.ts +4 -0
- package/dist/types/widgets-v2/pie/types.d.ts +50 -0
- package/dist/types/widgets-v2/provider/widget-provider.d.ts +32 -0
- package/dist/types/widgets-v2/range/index.d.ts +4 -0
- package/dist/types/widgets-v2/range/range-ui.d.ts +19 -0
- package/dist/types/widgets-v2/range/range.d.ts +19 -0
- package/dist/types/widgets-v2/range/skeleton.d.ts +9 -0
- package/dist/types/widgets-v2/range/style.d.ts +40 -0
- package/dist/types/widgets-v2/range/types.d.ts +37 -0
- package/dist/types/widgets-v2/scatterplot/download.d.ts +16 -0
- package/dist/types/widgets-v2/scatterplot/download.test.d.ts +1 -0
- package/dist/types/widgets-v2/scatterplot/index.d.ts +5 -0
- package/dist/types/widgets-v2/scatterplot/options.d.ts +42 -0
- package/dist/types/widgets-v2/scatterplot/options.test.d.ts +1 -0
- package/dist/types/widgets-v2/scatterplot/skeleton.d.ts +12 -0
- package/dist/types/widgets-v2/scatterplot/transforms.d.ts +17 -0
- package/dist/types/widgets-v2/scatterplot/transforms.test.d.ts +1 -0
- package/dist/types/widgets-v2/scatterplot/types.d.ts +50 -0
- package/dist/types/widgets-v2/selection-summary/labels.d.ts +6 -0
- package/dist/types/widgets-v2/selection-summary/selection-summary.d.ts +22 -0
- package/dist/types/widgets-v2/selection-summary/style.d.ts +23 -0
- package/dist/types/widgets-v2/spread/download.d.ts +15 -0
- package/dist/types/widgets-v2/spread/download.test.d.ts +1 -0
- package/dist/types/widgets-v2/spread/index.d.ts +6 -0
- package/dist/types/widgets-v2/spread/separator.d.ts +7 -0
- package/dist/types/widgets-v2/spread/skeleton.d.ts +9 -0
- package/dist/types/widgets-v2/spread/spread-ui.d.ts +18 -0
- package/dist/types/widgets-v2/spread/spread.d.ts +5 -0
- package/dist/types/widgets-v2/spread/types.d.ts +25 -0
- package/dist/types/widgets-v2/state/labels.d.ts +7 -0
- package/dist/types/widgets-v2/state/labels.test.d.ts +1 -0
- package/dist/types/widgets-v2/state/style.d.ts +19 -0
- package/dist/types/widgets-v2/state/widget-state.d.ts +19 -0
- package/dist/types/widgets-v2/stores/index.d.ts +8 -0
- package/dist/types/widgets-v2/stores/pipeline-middleware.d.ts +5 -0
- package/dist/types/widgets-v2/stores/pipeline-middleware.test.d.ts +1 -0
- package/dist/types/widgets-v2/stores/transforms.d.ts +4 -0
- package/dist/types/widgets-v2/stores/transforms.test.d.ts +1 -0
- package/dist/types/widgets-v2/stores/types.d.ts +55 -0
- package/dist/types/widgets-v2/stores/use-echart-instance.d.ts +15 -0
- package/dist/types/widgets-v2/stores/use-transform-enabled.d.ts +17 -0
- package/dist/types/widgets-v2/stores/use-transform.d.ts +12 -0
- package/dist/types/widgets-v2/stores/widget-context.d.ts +2 -0
- package/dist/types/widgets-v2/stores/widget-store-registry.d.ts +74 -0
- package/dist/types/widgets-v2/stores/widget-store-registry.test.d.ts +1 -0
- package/dist/types/widgets-v2/subheader/style.d.ts +10 -0
- package/dist/types/widgets-v2/subheader/subheader.d.ts +11 -0
- package/dist/types/widgets-v2/table/download.d.ts +18 -0
- package/dist/types/widgets-v2/table/download.test.d.ts +1 -0
- package/dist/types/widgets-v2/table/helpers.d.ts +32 -0
- package/dist/types/widgets-v2/table/helpers.test.d.ts +1 -0
- package/dist/types/widgets-v2/table/index.d.ts +7 -0
- package/dist/types/widgets-v2/table/labels.d.ts +22 -0
- package/dist/types/widgets-v2/table/skeleton.d.ts +22 -0
- package/dist/types/widgets-v2/table/style.d.ts +44 -0
- package/dist/types/widgets-v2/table/table-ui.d.ts +38 -0
- package/dist/types/widgets-v2/table/table.d.ts +50 -0
- package/dist/types/widgets-v2/table/types.d.ts +37 -0
- package/dist/types/widgets-v2/test-utils.d.ts +52 -0
- package/dist/types/widgets-v2/timeseries/download.d.ts +17 -0
- package/dist/types/widgets-v2/timeseries/download.test.d.ts +1 -0
- package/dist/types/widgets-v2/timeseries/index.d.ts +4 -0
- package/dist/types/widgets-v2/timeseries/options.d.ts +39 -0
- package/dist/types/widgets-v2/timeseries/options.test.d.ts +1 -0
- package/dist/types/widgets-v2/timeseries/skeleton.d.ts +8 -0
- package/dist/types/widgets-v2/timeseries/types.d.ts +56 -0
- package/dist/types/widgets-v2/toolbox/labels.d.ts +5 -0
- package/dist/types/widgets-v2/toolbox/style.d.ts +30 -0
- package/dist/types/widgets-v2/toolbox/toolbox.d.ts +49 -0
- package/dist/types/widgets-v2/utils/data-zoom-layout.d.ts +11 -0
- package/dist/types/widgets-v2/utils/index.d.ts +2 -0
- package/dist/types/widgets-v2/utils/merge-options.d.ts +12 -0
- package/dist/types/widgets-v2/utils/merge-options.test.d.ts +1 -0
- package/dist/types/widgets-v2/wrapper/index.d.ts +4 -0
- package/dist/types/widgets-v2/wrapper/labels.d.ts +6 -0
- package/dist/types/widgets-v2/wrapper/style.d.ts +111 -0
- package/dist/types/widgets-v2/wrapper/widget-actions.d.ts +22 -0
- package/dist/types/widgets-v2/wrapper/widget-content.d.ts +12 -0
- package/dist/types/widgets-v2/wrapper/widget-wrapper.d.ts +51 -0
- package/dist/use-transform-DXPN3nY7.js +110 -0
- package/dist/use-transform-DXPN3nY7.js.map +1 -0
- package/dist/widget-context-DTGO0Yta.js +13 -0
- package/dist/widget-context-DTGO0Yta.js.map +1 -0
- package/dist/widget-store-registry-_W4Z4xp-.js +178 -0
- package/dist/widget-store-registry-_W4Z4xp-.js.map +1 -0
- package/dist/widgets/bar.js +14 -13
- package/dist/widgets/bar.js.map +1 -1
- package/dist/widgets/histogram.js +8 -7
- package/dist/widgets/histogram.js.map +1 -1
- package/dist/widgets/pie.js +19 -18
- package/dist/widgets/pie.js.map +1 -1
- package/dist/widgets/scatterplot.js +8 -7
- package/dist/widgets/scatterplot.js.map +1 -1
- package/dist/widgets/timeseries.js +11 -10
- package/dist/widgets/timeseries.js.map +1 -1
- package/dist/widgets/utils.js +8 -7
- package/dist/widgets/utils.js.map +1 -1
- package/dist/widgets-v2/actions.js +43 -0
- package/dist/widgets-v2/actions.js.map +1 -0
- package/dist/widgets-v2/bar.js +327 -0
- package/dist/widgets-v2/bar.js.map +1 -0
- package/dist/widgets-v2/category.js +104 -0
- package/dist/widgets-v2/category.js.map +1 -0
- package/dist/widgets-v2/echart.js +57 -0
- package/dist/widgets-v2/echart.js.map +1 -0
- package/dist/widgets-v2/formula.js +74 -0
- package/dist/widgets-v2/formula.js.map +1 -0
- package/dist/widgets-v2/histogram.js +350 -0
- package/dist/widgets-v2/histogram.js.map +1 -0
- package/dist/widgets-v2/markdown.js +68 -0
- package/dist/widgets-v2/markdown.js.map +1 -0
- package/dist/widgets-v2/pie.js +381 -0
- package/dist/widgets-v2/pie.js.map +1 -0
- package/dist/widgets-v2/range.js +52 -0
- package/dist/widgets-v2/range.js.map +1 -0
- package/dist/widgets-v2/scatterplot.js +405 -0
- package/dist/widgets-v2/scatterplot.js.map +1 -0
- package/dist/widgets-v2/spread.js +72 -0
- package/dist/widgets-v2/spread.js.map +1 -0
- package/dist/widgets-v2/stores.js +42 -0
- package/dist/widgets-v2/stores.js.map +1 -0
- package/dist/widgets-v2/table.js +78 -0
- package/dist/widgets-v2/table.js.map +1 -0
- package/dist/widgets-v2/timeseries.js +352 -0
- package/dist/widgets-v2/timeseries.js.map +1 -0
- package/dist/widgets-v2/utils.js +7 -0
- package/dist/widgets-v2/utils.js.map +1 -0
- package/dist/widgets-v2.js +953 -0
- package/dist/widgets-v2.js.map +1 -0
- package/package.json +73 -5
- package/src/components/lasso-tool/chip.test.tsx +176 -0
- package/src/components/lasso-tool/lasso-tool-inline.test.tsx +171 -0
- package/src/components/lasso-tool/lasso-tool.test.tsx +198 -0
- package/src/components/list-data/list-data.test.tsx +73 -0
- package/src/components/no-data-alert/no-data-alert.test.tsx +38 -0
- package/src/components/responsive-drawer/responsive-drawer.test.tsx +68 -0
- package/src/widgets/actions/brush-toggle/brush-overlay.test.tsx +465 -0
- package/src/widgets/actions/brush-toggle/brush-toggle.test.tsx +208 -0
- package/src/widgets/actions/change-column/change-column-dnd.test.tsx +193 -0
- package/src/widgets/actions/change-column/sortable-column-item.test.tsx +124 -0
- package/src/widgets/actions/zoom-toggle/zoom-toggle.test.tsx +322 -0
- package/src/widgets/category/components/category-rows.test.tsx +213 -0
- package/src/widgets/echart/utils.test.ts +277 -0
- package/src/widgets/formula/config.test.ts +37 -0
- package/src/widgets/range/components/range-item.test.tsx +243 -0
- package/src/widgets/stores/widget-store-branches.test.ts +275 -0
- package/src/widgets/table/config.test.ts +65 -0
- package/src/widgets/utils/chart-config/option-builders.test.ts +188 -0
- package/src/widgets-v2/PERFORMANCE.md +189 -0
- package/src/widgets-v2/actions/brush-toggle/brush-toggle.test.tsx +180 -0
- package/src/widgets-v2/actions/brush-toggle/brush-toggle.tsx +154 -0
- package/src/widgets-v2/actions/brush-toggle/index.ts +3 -0
- package/src/widgets-v2/actions/brush-toggle/labels.ts +9 -0
- package/src/widgets-v2/actions/brush-toggle/style.ts +11 -0
- package/src/widgets-v2/actions/brush-toggle/transforms.test.ts +47 -0
- package/src/widgets-v2/actions/brush-toggle/transforms.ts +31 -0
- package/src/widgets-v2/actions/change-column/change-column-icon.tsx +14 -0
- package/src/widgets-v2/actions/change-column/change-column.test.tsx +59 -0
- package/src/widgets-v2/actions/change-column/change-column.tsx +180 -0
- package/src/widgets-v2/actions/change-column/index.ts +7 -0
- package/src/widgets-v2/actions/change-column/labels.ts +9 -0
- package/src/widgets-v2/actions/change-column/sortable-column-item.tsx +56 -0
- package/src/widgets-v2/actions/change-column/style.ts +32 -0
- package/src/widgets-v2/actions/change-column/types.ts +11 -0
- package/src/widgets-v2/actions/download/download.test.tsx +327 -0
- package/src/widgets-v2/actions/download/download.tsx +144 -0
- package/src/widgets-v2/actions/download/exports.test.tsx +198 -0
- package/src/widgets-v2/actions/download/exports.ts +115 -0
- package/src/widgets-v2/actions/download/icons.tsx +26 -0
- package/src/widgets-v2/actions/download/index.ts +13 -0
- package/src/widgets-v2/actions/download/labels.ts +16 -0
- package/src/widgets-v2/actions/download/png-item.test.tsx +72 -0
- package/src/widgets-v2/actions/download/png-item.tsx +52 -0
- package/src/widgets-v2/actions/download/style.ts +3 -0
- package/src/widgets-v2/actions/download/types.ts +32 -0
- package/src/widgets-v2/actions/fullscreen/fullscreen.test.tsx +150 -0
- package/src/widgets-v2/actions/fullscreen/fullscreen.tsx +230 -0
- package/src/widgets-v2/actions/fullscreen/index.ts +7 -0
- package/src/widgets-v2/actions/fullscreen/labels.ts +9 -0
- package/src/widgets-v2/actions/fullscreen/style.ts +59 -0
- package/src/widgets-v2/actions/fullscreen/types.ts +15 -0
- package/src/widgets-v2/actions/index.ts +82 -0
- package/src/widgets-v2/actions/lock-selection/index.ts +10 -0
- package/src/widgets-v2/actions/lock-selection/labels.ts +11 -0
- package/src/widgets-v2/actions/lock-selection/lock-selection.test.tsx +187 -0
- package/src/widgets-v2/actions/lock-selection/lock-selection.tsx +130 -0
- package/src/widgets-v2/actions/lock-selection/style.ts +11 -0
- package/src/widgets-v2/actions/lock-selection/transforms.ts +27 -0
- package/src/widgets-v2/actions/relative-data/index.ts +3 -0
- package/src/widgets-v2/actions/relative-data/labels.ts +9 -0
- package/src/widgets-v2/actions/relative-data/relative-data.test.tsx +71 -0
- package/src/widgets-v2/actions/relative-data/relative-data.tsx +107 -0
- package/src/widgets-v2/actions/relative-data/style.ts +11 -0
- package/src/widgets-v2/actions/relative-data/transforms.test.ts +151 -0
- package/src/widgets-v2/actions/relative-data/transforms.ts +70 -0
- package/src/widgets-v2/actions/searcher/filter.ts +28 -0
- package/src/widgets-v2/actions/searcher/index.ts +8 -0
- package/src/widgets-v2/actions/searcher/labels.ts +13 -0
- package/src/widgets-v2/actions/searcher/searcher-toggle.tsx +91 -0
- package/src/widgets-v2/actions/searcher/searcher.test.tsx +92 -0
- package/src/widgets-v2/actions/searcher/searcher.tsx +112 -0
- package/src/widgets-v2/actions/searcher/style.ts +15 -0
- package/src/widgets-v2/actions/stack-toggle/index.ts +3 -0
- package/src/widgets-v2/actions/stack-toggle/labels.ts +9 -0
- package/src/widgets-v2/actions/stack-toggle/stack-toggle.test.tsx +61 -0
- package/src/widgets-v2/actions/stack-toggle/stack-toggle.tsx +54 -0
- package/src/widgets-v2/actions/stack-toggle/style.ts +11 -0
- package/src/widgets-v2/actions/stack-toggle/transforms.test.ts +43 -0
- package/src/widgets-v2/actions/stack-toggle/transforms.ts +25 -0
- package/src/widgets-v2/actions/zoom-toggle/index.ts +9 -0
- package/src/widgets-v2/actions/zoom-toggle/labels.ts +9 -0
- package/src/widgets-v2/actions/zoom-toggle/style.ts +11 -0
- package/src/widgets-v2/actions/zoom-toggle/transforms.test.ts +148 -0
- package/src/widgets-v2/actions/zoom-toggle/transforms.ts +171 -0
- package/src/widgets-v2/actions/zoom-toggle/zoom-toggle.test.tsx +107 -0
- package/src/widgets-v2/actions/zoom-toggle/zoom-toggle.tsx +106 -0
- package/src/widgets-v2/bar/download.test.tsx +91 -0
- package/src/widgets-v2/bar/download.tsx +66 -0
- package/src/widgets-v2/bar/index.ts +10 -0
- package/src/widgets-v2/bar/options.test.ts +317 -0
- package/src/widgets-v2/bar/options.ts +326 -0
- package/src/widgets-v2/bar/skeleton.test.tsx +19 -0
- package/src/widgets-v2/bar/skeleton.tsx +69 -0
- package/src/widgets-v2/bar/types.ts +46 -0
- package/src/widgets-v2/category/category-ui.test.tsx +746 -0
- package/src/widgets-v2/category/category-ui.tsx +389 -0
- package/src/widgets-v2/category/category.relative-data.test.tsx +107 -0
- package/src/widgets-v2/category/category.stack-toggle.test.tsx +85 -0
- package/src/widgets-v2/category/category.test.tsx +305 -0
- package/src/widgets-v2/category/category.tsx +121 -0
- package/src/widgets-v2/category/components/category-bar-stacked.test.tsx +121 -0
- package/src/widgets-v2/category/components/category-bar-stacked.tsx +73 -0
- package/src/widgets-v2/category/components/category-bar.test.tsx +64 -0
- package/src/widgets-v2/category/components/category-bar.tsx +49 -0
- package/src/widgets-v2/category/components/category-legend.test.tsx +51 -0
- package/src/widgets-v2/category/components/category-legend.tsx +39 -0
- package/src/widgets-v2/category/components/category-row-multi.tsx +86 -0
- package/src/widgets-v2/category/components/category-row-other.test.tsx +28 -0
- package/src/widgets-v2/category/components/category-row-other.tsx +33 -0
- package/src/widgets-v2/category/components/category-row-single.tsx +76 -0
- package/src/widgets-v2/category/components/category-row-stacked.test.tsx +244 -0
- package/src/widgets-v2/category/components/category-row-stacked.tsx +99 -0
- package/src/widgets-v2/category/download.test.ts +71 -0
- package/src/widgets-v2/category/download.ts +54 -0
- package/src/widgets-v2/category/index.ts +32 -0
- package/src/widgets-v2/category/skeleton.test.tsx +26 -0
- package/src/widgets-v2/category/skeleton.tsx +74 -0
- package/src/widgets-v2/category/style.ts +290 -0
- package/src/widgets-v2/category/types.ts +54 -0
- package/src/widgets-v2/echart/echart-ui.test.tsx +232 -0
- package/src/widgets-v2/echart/echart-ui.tsx +184 -0
- package/src/widgets-v2/echart/echart.test.tsx +229 -0
- package/src/widgets-v2/echart/echart.tsx +199 -0
- package/src/widgets-v2/echart/index.ts +22 -0
- package/src/widgets-v2/echart/shared-resize-observer.test.ts +91 -0
- package/src/widgets-v2/echart/shared-resize-observer.ts +56 -0
- package/src/widgets-v2/echart/style.ts +8 -0
- package/src/widgets-v2/echart/use-chart-selection.test.tsx +118 -0
- package/src/widgets-v2/echart/use-chart-selection.ts +115 -0
- package/src/widgets-v2/formula/delta.tsx +61 -0
- package/src/widgets-v2/formula/download.test.tsx +65 -0
- package/src/widgets-v2/formula/download.tsx +69 -0
- package/src/widgets-v2/formula/formula-ui.test.tsx +91 -0
- package/src/widgets-v2/formula/formula-ui.tsx +66 -0
- package/src/widgets-v2/formula/formula.test.tsx +50 -0
- package/src/widgets-v2/formula/formula.tsx +34 -0
- package/src/widgets-v2/formula/index.ts +17 -0
- package/src/widgets-v2/formula/note.tsx +25 -0
- package/src/widgets-v2/formula/prefix.tsx +25 -0
- package/src/widgets-v2/formula/series.tsx +67 -0
- package/src/widgets-v2/formula/skeleton.test.tsx +21 -0
- package/src/widgets-v2/formula/skeleton.tsx +27 -0
- package/src/widgets-v2/formula/style.ts +31 -0
- package/src/widgets-v2/formula/subcomponents.test.tsx +107 -0
- package/src/widgets-v2/formula/suffix.tsx +25 -0
- package/src/widgets-v2/formula/types.ts +44 -0
- package/src/widgets-v2/formula/value.tsx +31 -0
- package/src/widgets-v2/histogram/download.test.ts +94 -0
- package/src/widgets-v2/histogram/download.ts +60 -0
- package/src/widgets-v2/histogram/index.ts +10 -0
- package/src/widgets-v2/histogram/options.test.ts +304 -0
- package/src/widgets-v2/histogram/options.ts +337 -0
- package/src/widgets-v2/histogram/skeleton.test.tsx +16 -0
- package/src/widgets-v2/histogram/skeleton.tsx +70 -0
- package/src/widgets-v2/histogram/transforms.test.ts +46 -0
- package/src/widgets-v2/histogram/transforms.ts +30 -0
- package/src/widgets-v2/histogram/types.ts +51 -0
- package/src/widgets-v2/index.ts +201 -0
- package/src/widgets-v2/markdown/download.test.ts +66 -0
- package/src/widgets-v2/markdown/download.ts +53 -0
- package/src/widgets-v2/markdown/index.ts +6 -0
- package/src/widgets-v2/markdown/markdown-content.test.tsx +155 -0
- package/src/widgets-v2/markdown/markdown-content.tsx +72 -0
- package/src/widgets-v2/markdown/markdown-ui.test.tsx +75 -0
- package/src/widgets-v2/markdown/markdown-ui.tsx +55 -0
- package/src/widgets-v2/markdown/markdown.test.tsx +39 -0
- package/src/widgets-v2/markdown/markdown.tsx +17 -0
- package/src/widgets-v2/markdown/skeleton.test.tsx +15 -0
- package/src/widgets-v2/markdown/skeleton.tsx +32 -0
- package/src/widgets-v2/markdown/style.ts +53 -0
- package/src/widgets-v2/markdown/types.ts +4 -0
- package/src/widgets-v2/note/labels.ts +9 -0
- package/src/widgets-v2/note/style.ts +26 -0
- package/src/widgets-v2/note/widget-note.test.tsx +158 -0
- package/src/widgets-v2/note/widget-note.tsx +172 -0
- package/src/widgets-v2/pie/download.test.ts +78 -0
- package/src/widgets-v2/pie/download.ts +55 -0
- package/src/widgets-v2/pie/index.ts +10 -0
- package/src/widgets-v2/pie/options.test.ts +585 -0
- package/src/widgets-v2/pie/options.ts +509 -0
- package/src/widgets-v2/pie/skeleton.test.tsx +17 -0
- package/src/widgets-v2/pie/skeleton.tsx +32 -0
- package/src/widgets-v2/pie/types.ts +55 -0
- package/src/widgets-v2/provider/widget-provider.test.tsx +119 -0
- package/src/widgets-v2/provider/widget-provider.tsx +111 -0
- package/src/widgets-v2/range/index.ts +4 -0
- package/src/widgets-v2/range/range-ui.test.tsx +130 -0
- package/src/widgets-v2/range/range-ui.tsx +211 -0
- package/src/widgets-v2/range/range.test.tsx +68 -0
- package/src/widgets-v2/range/range.tsx +46 -0
- package/src/widgets-v2/range/skeleton.test.tsx +17 -0
- package/src/widgets-v2/range/skeleton.tsx +47 -0
- package/src/widgets-v2/range/style.ts +41 -0
- package/src/widgets-v2/range/types.ts +37 -0
- package/src/widgets-v2/scatterplot/download.test.ts +71 -0
- package/src/widgets-v2/scatterplot/download.ts +54 -0
- package/src/widgets-v2/scatterplot/index.ts +11 -0
- package/src/widgets-v2/scatterplot/options.test.ts +399 -0
- package/src/widgets-v2/scatterplot/options.ts +421 -0
- package/src/widgets-v2/scatterplot/skeleton.test.tsx +17 -0
- package/src/widgets-v2/scatterplot/skeleton.tsx +84 -0
- package/src/widgets-v2/scatterplot/transforms.test.ts +97 -0
- package/src/widgets-v2/scatterplot/transforms.ts +38 -0
- package/src/widgets-v2/scatterplot/types.ts +55 -0
- package/src/widgets-v2/selection-summary/labels.ts +11 -0
- package/src/widgets-v2/selection-summary/selection-summary.test.tsx +53 -0
- package/src/widgets-v2/selection-summary/selection-summary.tsx +62 -0
- package/src/widgets-v2/selection-summary/style.ts +23 -0
- package/src/widgets-v2/spread/download.test.ts +64 -0
- package/src/widgets-v2/spread/download.ts +59 -0
- package/src/widgets-v2/spread/index.ts +6 -0
- package/src/widgets-v2/spread/separator.tsx +11 -0
- package/src/widgets-v2/spread/skeleton.test.tsx +17 -0
- package/src/widgets-v2/spread/skeleton.tsx +38 -0
- package/src/widgets-v2/spread/spread-ui.test.tsx +108 -0
- package/src/widgets-v2/spread/spread-ui.tsx +52 -0
- package/src/widgets-v2/spread/spread.test.tsx +50 -0
- package/src/widgets-v2/spread/spread.tsx +31 -0
- package/src/widgets-v2/spread/types.ts +27 -0
- package/src/widgets-v2/state/labels.test.ts +33 -0
- package/src/widgets-v2/state/labels.ts +20 -0
- package/src/widgets-v2/state/style.ts +25 -0
- package/src/widgets-v2/state/widget-state.test.tsx +294 -0
- package/src/widgets-v2/state/widget-state.tsx +184 -0
- package/src/widgets-v2/stores/index.ts +49 -0
- package/src/widgets-v2/stores/pipeline-middleware.test.ts +187 -0
- package/src/widgets-v2/stores/pipeline-middleware.ts +91 -0
- package/src/widgets-v2/stores/transforms.test.ts +162 -0
- package/src/widgets-v2/stores/transforms.ts +70 -0
- package/src/widgets-v2/stores/types.ts +64 -0
- package/src/widgets-v2/stores/use-echart-instance.test.tsx +91 -0
- package/src/widgets-v2/stores/use-echart-instance.ts +29 -0
- package/src/widgets-v2/stores/use-transform-enabled.test.tsx +127 -0
- package/src/widgets-v2/stores/use-transform-enabled.ts +25 -0
- package/src/widgets-v2/stores/use-transform.test.tsx +262 -0
- package/src/widgets-v2/stores/use-transform.ts +158 -0
- package/src/widgets-v2/stores/widget-context.test.tsx +58 -0
- package/src/widgets-v2/stores/widget-context.ts +15 -0
- package/src/widgets-v2/stores/widget-store-registry.test.ts +292 -0
- package/src/widgets-v2/stores/widget-store-registry.ts +248 -0
- package/src/widgets-v2/subheader/style.ts +12 -0
- package/src/widgets-v2/subheader/subheader.test.tsx +30 -0
- package/src/widgets-v2/subheader/subheader.tsx +16 -0
- package/src/widgets-v2/table/download.test.ts +75 -0
- package/src/widgets-v2/table/download.ts +47 -0
- package/src/widgets-v2/table/helpers.test.ts +214 -0
- package/src/widgets-v2/table/helpers.ts +136 -0
- package/src/widgets-v2/table/index.ts +23 -0
- package/src/widgets-v2/table/labels.tsx +41 -0
- package/src/widgets-v2/table/skeleton.test.tsx +26 -0
- package/src/widgets-v2/table/skeleton.tsx +65 -0
- package/src/widgets-v2/table/style.ts +46 -0
- package/src/widgets-v2/table/table-ui.test.tsx +200 -0
- package/src/widgets-v2/table/table-ui.tsx +331 -0
- package/src/widgets-v2/table/table.test.tsx +119 -0
- package/src/widgets-v2/table/table.tsx +174 -0
- package/src/widgets-v2/table/types.ts +44 -0
- package/src/widgets-v2/test-utils.ts +107 -0
- package/src/widgets-v2/timeseries/download.test.ts +95 -0
- package/src/widgets-v2/timeseries/download.ts +86 -0
- package/src/widgets-v2/timeseries/index.ts +10 -0
- package/src/widgets-v2/timeseries/options.test.ts +379 -0
- package/src/widgets-v2/timeseries/options.ts +341 -0
- package/src/widgets-v2/timeseries/skeleton.test.tsx +13 -0
- package/src/widgets-v2/timeseries/skeleton.tsx +76 -0
- package/src/widgets-v2/timeseries/types.ts +61 -0
- package/src/widgets-v2/toolbox/labels.ts +9 -0
- package/src/widgets-v2/toolbox/style.ts +33 -0
- package/src/widgets-v2/toolbox/toolbox.test.tsx +200 -0
- package/src/widgets-v2/toolbox/toolbox.tsx +309 -0
- package/src/widgets-v2/utils/data-zoom-layout.ts +26 -0
- package/src/widgets-v2/utils/index.ts +2 -0
- package/src/widgets-v2/utils/merge-options.test.ts +52 -0
- package/src/widgets-v2/utils/merge-options.ts +50 -0
- package/src/widgets-v2/wrapper/index.ts +14 -0
- package/src/widgets-v2/wrapper/labels.ts +11 -0
- package/src/widgets-v2/wrapper/style.ts +134 -0
- package/src/widgets-v2/wrapper/widget-actions.test.tsx +52 -0
- package/src/widgets-v2/wrapper/widget-actions.tsx +43 -0
- package/src/widgets-v2/wrapper/widget-content.test.tsx +27 -0
- package/src/widgets-v2/wrapper/widget-content.tsx +29 -0
- package/src/widgets-v2/wrapper/widget-wrapper.test.tsx +159 -0
- package/src/widgets-v2/wrapper/widget-wrapper.tsx +178 -0
- package/dist/styles-BYTyKQFP.js.map +0 -1
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react'
|
|
2
|
+
import type * as echarts from 'echarts'
|
|
3
|
+
import {
|
|
4
|
+
applyTransforms,
|
|
5
|
+
setEchartInstance,
|
|
6
|
+
useWidgetId,
|
|
7
|
+
useWidgetShallow,
|
|
8
|
+
type Transform,
|
|
9
|
+
} from '../stores'
|
|
10
|
+
import { EchartUI, type EchartsEventHandler } from './echart-ui'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Default ECharts `replaceMerge` keys for every widget. `dataZoom` and
|
|
14
|
+
* `brush` are omitted so ZoomToggle / BrushToggle's user-driven runtime
|
|
15
|
+
* state (slider range, brushed areas in `multiple` mode) survives unrelated
|
|
16
|
+
* re-renders. `series` and `dataset` are also omitted: EchartUI fingerprints
|
|
17
|
+
* them per-render and adds them to `replaceMerge` only when their shape
|
|
18
|
+
* actually changes, keeping ECharts' per-series runtime state alive when
|
|
19
|
+
* only callback-style fields differ.
|
|
20
|
+
*
|
|
21
|
+
* Lives in this module (not the generic store) because it's an ECharts
|
|
22
|
+
* concept. Module-private — callers should not need it.
|
|
23
|
+
*/
|
|
24
|
+
const DEFAULT_REPLACE_MERGE: readonly string[] = ['toolbox']
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reactive context passed to every {@link OptionFactory} call so the
|
|
28
|
+
* factory can rebuild render-time pieces (axis label / tooltip formatters)
|
|
29
|
+
* from the live store. Drives RelativeData / consumer-formatter changes
|
|
30
|
+
* through to the chart without rebuilding the structural option.
|
|
31
|
+
*/
|
|
32
|
+
export interface OptionFactoryContext {
|
|
33
|
+
formatter?: (value: number) => string
|
|
34
|
+
labelFormatter?: (value: string | number) => string | number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The per-widget option factory — a single callable that owns BOTH phases
|
|
39
|
+
* of option construction:
|
|
40
|
+
*
|
|
41
|
+
* - **Structural phase** — when `option == null`, return the theme-aware
|
|
42
|
+
* structural option (tooltip / legend / color palette / series
|
|
43
|
+
* template, optionally merged with a consumer-supplied `optionsOverride`).
|
|
44
|
+
* No data is read. `<Widget.Echart>` calls the factory with
|
|
45
|
+
* `(undefined, undefined)` synchronously during render to derive the
|
|
46
|
+
* structural base; `configTransforms` (Stack/Zoom/Brush) then mutate it
|
|
47
|
+
* in the same render pass.
|
|
48
|
+
* - **Merge phase** — when `option` is defined, fuse `data` into the
|
|
49
|
+
* post-configTransforms option at fusion time. `<Widget.Echart>` calls
|
|
50
|
+
* the factory with `(transformed, data, ctx)` on every render.
|
|
51
|
+
*
|
|
52
|
+
* The two phases share a closure (the factory creator captures `theme`,
|
|
53
|
+
* `formatter`, `labelFormatter`, `seriesNames`, `selection`, `optionsOverride`,
|
|
54
|
+
* …), so structural and merge agree on the same widget configuration.
|
|
55
|
+
*
|
|
56
|
+
* The third arg `ctx` carries the **live** store-side formatters at the
|
|
57
|
+
* call site — distinct from the closure-time formatters because actions
|
|
58
|
+
* like RelativeData can install a percent formatter on the store after
|
|
59
|
+
* the factory was constructed. The merge phase reads from `ctx`; the
|
|
60
|
+
* structural phase typically uses the closure-time values.
|
|
61
|
+
*/
|
|
62
|
+
export type OptionFactory = (
|
|
63
|
+
option: echarts.EChartsOption | undefined,
|
|
64
|
+
data: unknown,
|
|
65
|
+
ctx?: OptionFactoryContext,
|
|
66
|
+
) => echarts.EChartsOption
|
|
67
|
+
|
|
68
|
+
export interface EchartProps {
|
|
69
|
+
/**
|
|
70
|
+
* The per-widget {@link OptionFactory}. Required — `<Widget.Echart>`
|
|
71
|
+
* derives the structural option from it (so configTransforms have a base
|
|
72
|
+
* to mutate) and fuses `state.data` into the post-pipeline option at
|
|
73
|
+
* render time. Wrap the factory creator in `useMemo` so its identity is
|
|
74
|
+
* stable across renders.
|
|
75
|
+
*/
|
|
76
|
+
optionFactory: OptionFactory
|
|
77
|
+
onEvents?: Record<string, EchartsEventHandler>
|
|
78
|
+
init?: echarts.EChartsInitOpts
|
|
79
|
+
className?: string
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
interface EchartSlice {
|
|
83
|
+
data: unknown
|
|
84
|
+
configTransforms: readonly Transform[]
|
|
85
|
+
formatter?: (value: number) => string
|
|
86
|
+
labelFormatter?: (value: string | number) => string | number
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const echartSelector = (s: {
|
|
90
|
+
data: unknown
|
|
91
|
+
configTransforms: readonly Transform[]
|
|
92
|
+
formatter?: (value: number) => string
|
|
93
|
+
labelFormatter?: (value: string | number) => string | number
|
|
94
|
+
}): EchartSlice => ({
|
|
95
|
+
data: s.data,
|
|
96
|
+
configTransforms: s.configTransforms,
|
|
97
|
+
formatter: s.formatter,
|
|
98
|
+
labelFormatter: s.labelFormatter,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Stateful Echart bridge — owns the entire ECharts coupling. The whole
|
|
103
|
+
* option pipeline lives here, not in the store:
|
|
104
|
+
*
|
|
105
|
+
* 1. **Structural** — `optionFactory(undefined, undefined)` produces the
|
|
106
|
+
* theme-aware base. Memoized on the factory identity, so the consumer's
|
|
107
|
+
* `useMemo` ID gates the rebuild.
|
|
108
|
+
* 2. **Transformed** — `applyTransforms(structural, configTransforms)`
|
|
109
|
+
* applies any registered configTransforms (Stack/Zoom/Brush) over the
|
|
110
|
+
* structural base. Memoized on `[structural, configTransforms]`.
|
|
111
|
+
* 3. **`replaceMerge`** — derived from the enabled configTransforms'
|
|
112
|
+
* `replaceMergeKeys`, deduped and sorted, seeded with
|
|
113
|
+
* {@link DEFAULT_REPLACE_MERGE}. Memoized on `[configTransforms]` so
|
|
114
|
+
* ECharts sees a stable array reference across non-transform changes.
|
|
115
|
+
* 4. **Merge** — `optionFactory(transformed, data, ctx)` fuses post-
|
|
116
|
+
* pipeline data into the option. Reactive `ctx` carries the live store
|
|
117
|
+
* formatters so RelativeData's percent formatter flows through without
|
|
118
|
+
* a structural rebuild.
|
|
119
|
+
*
|
|
120
|
+
* The `<Widget.Provider>` doesn't know about the factory at all: it stays
|
|
121
|
+
* a renderer-agnostic shell. The `ProviderProps` surface has no ECharts
|
|
122
|
+
* coupling, so non-Echart widgets don't transitively import the type.
|
|
123
|
+
*/
|
|
124
|
+
export function Echart({
|
|
125
|
+
optionFactory,
|
|
126
|
+
onEvents,
|
|
127
|
+
init,
|
|
128
|
+
className,
|
|
129
|
+
}: EchartProps) {
|
|
130
|
+
const id = useWidgetId()
|
|
131
|
+
const slice = useWidgetShallow(id, echartSelector)
|
|
132
|
+
|
|
133
|
+
// Publish the live ECharts instance to the per-id registry so actions
|
|
134
|
+
// (e.g. `ZoomToggle`'s disable handler) can reach it imperatively. The
|
|
135
|
+
// callback identity is stable across renders (only `id` is in deps), so
|
|
136
|
+
// EchartUI's init effect doesn't see a fresh `onInstance` and re-init.
|
|
137
|
+
const onInstance = useCallback(
|
|
138
|
+
(chart: echarts.ECharts | null) => setEchartInstance(id, chart),
|
|
139
|
+
[id],
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
// Destructure so React Compiler sees specific deps instead of inferring
|
|
143
|
+
// the whole `slice` object. `useWidgetShallow` already shallow-compares
|
|
144
|
+
// the slice, so per-field deps drive each memo exactly when its inputs
|
|
145
|
+
// change.
|
|
146
|
+
const {
|
|
147
|
+
data: sliceData,
|
|
148
|
+
configTransforms,
|
|
149
|
+
formatter: sliceFormatter,
|
|
150
|
+
labelFormatter: sliceLabelFormatter,
|
|
151
|
+
} = slice
|
|
152
|
+
|
|
153
|
+
const structural = useMemo(
|
|
154
|
+
() => optionFactory(undefined, undefined),
|
|
155
|
+
[optionFactory],
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
const transformed = useMemo(
|
|
159
|
+
() =>
|
|
160
|
+
applyTransforms(structural, configTransforms) as echarts.EChartsOption,
|
|
161
|
+
[structural, configTransforms],
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
const replaceMerge = useMemo(() => {
|
|
165
|
+
const keys = new Set<string>(DEFAULT_REPLACE_MERGE)
|
|
166
|
+
for (const xf of configTransforms) {
|
|
167
|
+
if (xf.enabled && xf.replaceMergeKeys?.length) {
|
|
168
|
+
for (const k of xf.replaceMergeKeys) keys.add(k)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return Array.from(keys).sort()
|
|
172
|
+
}, [configTransforms])
|
|
173
|
+
|
|
174
|
+
const option = useMemo(
|
|
175
|
+
() =>
|
|
176
|
+
optionFactory(transformed, sliceData, {
|
|
177
|
+
formatter: sliceFormatter,
|
|
178
|
+
labelFormatter: sliceLabelFormatter,
|
|
179
|
+
}),
|
|
180
|
+
[
|
|
181
|
+
optionFactory,
|
|
182
|
+
transformed,
|
|
183
|
+
sliceData,
|
|
184
|
+
sliceFormatter,
|
|
185
|
+
sliceLabelFormatter,
|
|
186
|
+
],
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<EchartUI
|
|
191
|
+
option={option}
|
|
192
|
+
replaceMerge={replaceMerge}
|
|
193
|
+
onEvents={onEvents}
|
|
194
|
+
init={init}
|
|
195
|
+
onInstance={onInstance}
|
|
196
|
+
className={className}
|
|
197
|
+
/>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export {
|
|
2
|
+
EchartUI,
|
|
3
|
+
DEFAULT_INIT_OPTS,
|
|
4
|
+
type EchartUIProps,
|
|
5
|
+
type EchartsEventHandler,
|
|
6
|
+
} from './echart-ui'
|
|
7
|
+
export {
|
|
8
|
+
Echart,
|
|
9
|
+
type EchartProps,
|
|
10
|
+
type OptionFactory,
|
|
11
|
+
type OptionFactoryContext,
|
|
12
|
+
} from './echart'
|
|
13
|
+
export {
|
|
14
|
+
useChartSelection,
|
|
15
|
+
type SelectionKey,
|
|
16
|
+
type UseChartSelectionOptions,
|
|
17
|
+
type ChartSelectionWiring,
|
|
18
|
+
} from './use-chart-selection'
|
|
19
|
+
export {
|
|
20
|
+
observeResize,
|
|
21
|
+
__resetSharedResizeObserver,
|
|
22
|
+
} from './shared-resize-observer'
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
__resetSharedResizeObserver,
|
|
4
|
+
observeResize,
|
|
5
|
+
} from './shared-resize-observer'
|
|
6
|
+
|
|
7
|
+
// Track every ResizeObserver instance created in the test run so we can
|
|
8
|
+
// assert on construction / disconnect lifecycle. The shared module is a
|
|
9
|
+
// singleton — between tests we reset both its state and the mock.
|
|
10
|
+
const instances: {
|
|
11
|
+
observe: ReturnType<typeof vi.fn>
|
|
12
|
+
unobserve: ReturnType<typeof vi.fn>
|
|
13
|
+
disconnect: ReturnType<typeof vi.fn>
|
|
14
|
+
}[] = []
|
|
15
|
+
|
|
16
|
+
class MockResizeObserver {
|
|
17
|
+
observe = vi.fn()
|
|
18
|
+
unobserve = vi.fn()
|
|
19
|
+
disconnect = vi.fn()
|
|
20
|
+
constructor() {
|
|
21
|
+
instances.push(this)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
__resetSharedResizeObserver()
|
|
27
|
+
instances.length = 0
|
|
28
|
+
vi.stubGlobal('ResizeObserver', MockResizeObserver)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
__resetSharedResizeObserver()
|
|
33
|
+
vi.unstubAllGlobals()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('observeResize', () => {
|
|
37
|
+
it('lazily creates a single observer for the first subscriber', () => {
|
|
38
|
+
const el = document.createElement('div')
|
|
39
|
+
observeResize(el, () => undefined)
|
|
40
|
+
expect(instances).toHaveLength(1)
|
|
41
|
+
expect(instances[0]?.observe).toHaveBeenCalledWith(el)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('reuses the singleton observer for additional subscribers', () => {
|
|
45
|
+
const a = document.createElement('div')
|
|
46
|
+
const b = document.createElement('div')
|
|
47
|
+
observeResize(a, () => undefined)
|
|
48
|
+
observeResize(b, () => undefined)
|
|
49
|
+
expect(instances).toHaveLength(1)
|
|
50
|
+
expect(instances[0]?.observe).toHaveBeenCalledTimes(2)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('unobserves on unsubscribe but keeps the observer while other subscribers remain', () => {
|
|
54
|
+
const a = document.createElement('div')
|
|
55
|
+
const b = document.createElement('div')
|
|
56
|
+
const stopA = observeResize(a, () => undefined)
|
|
57
|
+
observeResize(b, () => undefined)
|
|
58
|
+
stopA()
|
|
59
|
+
expect(instances[0]?.unobserve).toHaveBeenCalledWith(a)
|
|
60
|
+
expect(instances[0]?.disconnect).not.toHaveBeenCalled()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('disconnects the observer once the last subscriber leaves', () => {
|
|
64
|
+
const a = document.createElement('div')
|
|
65
|
+
const stop = observeResize(a, () => undefined)
|
|
66
|
+
stop()
|
|
67
|
+
expect(instances[0]?.disconnect).toHaveBeenCalledTimes(1)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('returns a no-op cleanup when ResizeObserver is unavailable', () => {
|
|
71
|
+
vi.stubGlobal('ResizeObserver', undefined)
|
|
72
|
+
const el = document.createElement('div')
|
|
73
|
+
const cb = vi.fn()
|
|
74
|
+
const stop = observeResize(el, cb)
|
|
75
|
+
// No constructor calls — no instances tracked.
|
|
76
|
+
expect(instances).toHaveLength(0)
|
|
77
|
+
// Cleanup is safe to call.
|
|
78
|
+
expect(() => stop()).not.toThrow()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('re-instantiates the observer when a new subscriber arrives after disconnect', () => {
|
|
82
|
+
const a = document.createElement('div')
|
|
83
|
+
const b = document.createElement('div')
|
|
84
|
+
observeResize(a, () => undefined)()
|
|
85
|
+
expect(instances).toHaveLength(1)
|
|
86
|
+
expect(instances[0]?.disconnect).toHaveBeenCalledTimes(1)
|
|
87
|
+
observeResize(b, () => undefined)
|
|
88
|
+
expect(instances).toHaveLength(2)
|
|
89
|
+
expect(instances[1]?.observe).toHaveBeenCalledWith(b)
|
|
90
|
+
})
|
|
91
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
type ResizeCallback = () => void
|
|
2
|
+
|
|
3
|
+
const callbacks = new Map<Element, ResizeCallback>()
|
|
4
|
+
let observer: ResizeObserver | null = null
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the singleton ResizeObserver, lazily constructing it on first use.
|
|
8
|
+
* Returns `null` when `ResizeObserver` is not available in the global scope
|
|
9
|
+
* (SSR, very old browsers, or tests that intentionally remove it).
|
|
10
|
+
*/
|
|
11
|
+
function getObserver(): ResizeObserver | null {
|
|
12
|
+
if (typeof ResizeObserver === 'undefined') return null
|
|
13
|
+
observer ??= new ResizeObserver((entries) => {
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
const callback = callbacks.get(entry.target)
|
|
16
|
+
callback?.()
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
return observer
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const NOOP_CLEANUP = (): void => undefined
|
|
23
|
+
|
|
24
|
+
export function observeResize(
|
|
25
|
+
element: Element,
|
|
26
|
+
callback: ResizeCallback,
|
|
27
|
+
): () => void {
|
|
28
|
+
const ro = getObserver()
|
|
29
|
+
// Gracefully degrade when no ResizeObserver is available — consumers
|
|
30
|
+
// still see one initial measure() pass via their own effect; we just
|
|
31
|
+
// skip the subsequent resize-driven re-measures.
|
|
32
|
+
if (!ro) return NOOP_CLEANUP
|
|
33
|
+
callbacks.set(element, callback)
|
|
34
|
+
ro.observe(element)
|
|
35
|
+
return () => {
|
|
36
|
+
callbacks.delete(element)
|
|
37
|
+
if (observer) {
|
|
38
|
+
observer.unobserve(element)
|
|
39
|
+
// Disconnect the singleton once the last subscriber leaves so the
|
|
40
|
+
// observer doesn't outlive its consumers in SSR teardown / micro-
|
|
41
|
+
// frontend unmount scenarios. A subsequent observeResize() will
|
|
42
|
+
// lazily re-create it via getObserver().
|
|
43
|
+
if (callbacks.size === 0) {
|
|
44
|
+
observer.disconnect()
|
|
45
|
+
observer = null
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @internal — for tests only. */
|
|
52
|
+
export function __resetSharedResizeObserver(): void {
|
|
53
|
+
if (observer) observer.disconnect()
|
|
54
|
+
callbacks.clear()
|
|
55
|
+
observer = null
|
|
56
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { act, renderHook } from '@testing-library/react'
|
|
3
|
+
import { useChartSelection } from './use-chart-selection'
|
|
4
|
+
|
|
5
|
+
describe('useChartSelection', () => {
|
|
6
|
+
it('clicking an item toggles it into and out of the selection', () => {
|
|
7
|
+
const onSelectionChange = vi.fn()
|
|
8
|
+
const { result, rerender } = renderHook(
|
|
9
|
+
({ selection }: { selection: readonly string[] }) =>
|
|
10
|
+
useChartSelection<string>({
|
|
11
|
+
selection,
|
|
12
|
+
onSelectionChange,
|
|
13
|
+
keyFromClick: (p) => (p as { name?: string }).name ?? null,
|
|
14
|
+
keysFromBrush: () => [],
|
|
15
|
+
}),
|
|
16
|
+
{ initialProps: { selection: [] as readonly string[] } },
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
act(() => {
|
|
20
|
+
result.current.onEvents.click?.({ name: 'A' })
|
|
21
|
+
})
|
|
22
|
+
expect(onSelectionChange).toHaveBeenLastCalledWith(['A'])
|
|
23
|
+
|
|
24
|
+
rerender({ selection: ['A'] })
|
|
25
|
+
act(() => {
|
|
26
|
+
result.current.onEvents.click?.({ name: 'A' })
|
|
27
|
+
})
|
|
28
|
+
expect(onSelectionChange).toHaveBeenLastCalledWith([])
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('emits the brushed selection only on brushEnd (brushSelected just caches)', () => {
|
|
32
|
+
const onSelectionChange = vi.fn()
|
|
33
|
+
const { result } = renderHook(() =>
|
|
34
|
+
useChartSelection<number>({
|
|
35
|
+
selection: [99],
|
|
36
|
+
onSelectionChange,
|
|
37
|
+
keyFromClick: () => null,
|
|
38
|
+
keysFromBrush: (selected) => selected.flatMap((s) => s.dataIndex),
|
|
39
|
+
}),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
// Mid-drag updates fire brushSelected — these should NOT call back.
|
|
43
|
+
act(() => {
|
|
44
|
+
result.current.onEvents.brushSelected?.({
|
|
45
|
+
batch: [{ selected: [{ seriesIndex: 0, dataIndex: [3] }] }],
|
|
46
|
+
})
|
|
47
|
+
result.current.onEvents.brushSelected?.({
|
|
48
|
+
batch: [{ selected: [{ seriesIndex: 0, dataIndex: [3, 7] }] }],
|
|
49
|
+
})
|
|
50
|
+
result.current.onEvents.brushSelected?.({
|
|
51
|
+
batch: [{ selected: [{ seriesIndex: 0, dataIndex: [3, 7, 11] }] }],
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
expect(onSelectionChange).not.toHaveBeenCalled()
|
|
55
|
+
|
|
56
|
+
// Releasing the brush fires brushEnd — that's when we commit.
|
|
57
|
+
act(() => {
|
|
58
|
+
result.current.onEvents.brushEnd?.({})
|
|
59
|
+
})
|
|
60
|
+
expect(onSelectionChange).toHaveBeenCalledTimes(1)
|
|
61
|
+
expect(onSelectionChange).toHaveBeenLastCalledWith([3, 7, 11])
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('reports null `selection` when the consumer passes nothing or an empty list', () => {
|
|
65
|
+
const { result, rerender } = renderHook(
|
|
66
|
+
({ selection }: { selection?: readonly string[] }) =>
|
|
67
|
+
useChartSelection<string>({
|
|
68
|
+
selection,
|
|
69
|
+
onSelectionChange: () => undefined,
|
|
70
|
+
keyFromClick: () => null,
|
|
71
|
+
keysFromBrush: () => [],
|
|
72
|
+
}),
|
|
73
|
+
{
|
|
74
|
+
initialProps: { selection: undefined } as {
|
|
75
|
+
selection?: readonly string[]
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
)
|
|
79
|
+
expect(result.current.selection).toBeNull()
|
|
80
|
+
rerender({ selection: [] })
|
|
81
|
+
expect(result.current.selection).toBeNull()
|
|
82
|
+
rerender({ selection: ['A'] })
|
|
83
|
+
expect(result.current.selection).toEqual(['A'])
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('is a no-op when `onSelectionChange` is missing', () => {
|
|
87
|
+
const { result } = renderHook(() =>
|
|
88
|
+
useChartSelection<string>({
|
|
89
|
+
selection: [],
|
|
90
|
+
keyFromClick: (p) => (p as { name?: string }).name ?? null,
|
|
91
|
+
keysFromBrush: () => ['x'],
|
|
92
|
+
}),
|
|
93
|
+
)
|
|
94
|
+
// Neither call should throw — handler short-circuits without a callback.
|
|
95
|
+
expect(() => result.current.onEvents.click?.({ name: 'A' })).not.toThrow()
|
|
96
|
+
expect(() =>
|
|
97
|
+
result.current.onEvents.brushSelected?.({
|
|
98
|
+
batch: [{ selected: [{ seriesIndex: 0, dataIndex: [0] }] }],
|
|
99
|
+
}),
|
|
100
|
+
).not.toThrow()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('skips clicks where keyFromClick returns null (e.g. axis-label clicks)', () => {
|
|
104
|
+
const onSelectionChange = vi.fn()
|
|
105
|
+
const { result } = renderHook(() =>
|
|
106
|
+
useChartSelection<string>({
|
|
107
|
+
selection: [],
|
|
108
|
+
onSelectionChange,
|
|
109
|
+
keyFromClick: () => null,
|
|
110
|
+
keysFromBrush: () => [],
|
|
111
|
+
}),
|
|
112
|
+
)
|
|
113
|
+
act(() => {
|
|
114
|
+
result.current.onEvents.click?.({ name: 'A' })
|
|
115
|
+
})
|
|
116
|
+
expect(onSelectionChange).not.toHaveBeenCalled()
|
|
117
|
+
})
|
|
118
|
+
})
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef } from 'react'
|
|
2
|
+
import type { CallbackDataParams } from 'echarts/types/dist/shared'
|
|
3
|
+
import type { EchartsEventHandler } from './echart-ui'
|
|
4
|
+
|
|
5
|
+
export type SelectionKey = string | number
|
|
6
|
+
|
|
7
|
+
export interface UseChartSelectionOptions<K extends SelectionKey> {
|
|
8
|
+
/** Controlled selection. `undefined` is treated the same as `[]`. */
|
|
9
|
+
selection?: readonly K[]
|
|
10
|
+
/** Receives the next selection. When omitted the wiring is a no-op. */
|
|
11
|
+
onSelectionChange?: (next: readonly K[]) => void
|
|
12
|
+
/**
|
|
13
|
+
* Pull a selection key out of an ECharts `click` event. Return `null` to
|
|
14
|
+
* skip (e.g. a click on empty plot area). For Bar/Pie/Timeseries this is
|
|
15
|
+
* usually `(p) => p.name`; for Histogram/Scatterplot it's the dataIndex.
|
|
16
|
+
*/
|
|
17
|
+
keyFromClick: (params: CallbackDataParams) => K | null
|
|
18
|
+
/**
|
|
19
|
+
* Map a `brushSelected` payload's `selected[*]` entries (each carrying a
|
|
20
|
+
* `seriesIndex` + `dataIndex[]`) into the full set of selection keys for
|
|
21
|
+
* the brushed area. Called once per brush event.
|
|
22
|
+
*/
|
|
23
|
+
keysFromBrush: (
|
|
24
|
+
selected: readonly { seriesIndex: number; dataIndex: number[] }[],
|
|
25
|
+
) => K[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ChartSelectionWiring<K extends SelectionKey> {
|
|
29
|
+
/**
|
|
30
|
+
* Pass straight to `<Widget.Echart onEvents={…}>`. Wires `click` and
|
|
31
|
+
* `brushSelected` so the user's interactions reach `onSelectionChange`.
|
|
32
|
+
*/
|
|
33
|
+
onEvents: Record<string, EchartsEventHandler>
|
|
34
|
+
/**
|
|
35
|
+
* The current selection — `null` when the consumer didn't pass one or it's
|
|
36
|
+
* empty. Mergers should treat `null` as "no dimming" and a non-null array
|
|
37
|
+
* as "render only these as fully opaque, dim the rest".
|
|
38
|
+
*/
|
|
39
|
+
selection: readonly K[] | null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Translate ECharts' click + brush events into a consumer-owned selection
|
|
44
|
+
* with the expected dashboard semantics:
|
|
45
|
+
*
|
|
46
|
+
* - **Click toggles** — clicking an item adds it to the selection if
|
|
47
|
+
* absent, removes it if present.
|
|
48
|
+
* - **Brush replaces** — finishing a brush stroke overwrites the selection
|
|
49
|
+
* with whatever the brush covered (drag-to-empty clears).
|
|
50
|
+
*
|
|
51
|
+
* Wire the returned `onEvents` into `<Widget.Echart>` and feed
|
|
52
|
+
* `wiring.selection` to the widget's option factory so the merger can dim
|
|
53
|
+
* non-selected rows at fusion time.
|
|
54
|
+
*/
|
|
55
|
+
export function useChartSelection<K extends SelectionKey>({
|
|
56
|
+
selection,
|
|
57
|
+
onSelectionChange,
|
|
58
|
+
keyFromClick,
|
|
59
|
+
keysFromBrush,
|
|
60
|
+
}: UseChartSelectionOptions<K>): ChartSelectionWiring<K> {
|
|
61
|
+
const handleClick = useCallback(
|
|
62
|
+
(event: unknown) => {
|
|
63
|
+
if (!onSelectionChange) return
|
|
64
|
+
const params = event as CallbackDataParams
|
|
65
|
+
const key = keyFromClick(params)
|
|
66
|
+
if (key == null) return
|
|
67
|
+
const current = selection ?? []
|
|
68
|
+
const idx = current.indexOf(key)
|
|
69
|
+
const next =
|
|
70
|
+
idx === -1
|
|
71
|
+
? [...current, key]
|
|
72
|
+
: [...current.slice(0, idx), ...current.slice(idx + 1)]
|
|
73
|
+
onSelectionChange(next)
|
|
74
|
+
},
|
|
75
|
+
[selection, onSelectionChange, keyFromClick],
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
// ECharts fires `brushSelected` on every pointer-move while the user is
|
|
79
|
+
// drawing a brush, but we only want to push to `onSelectionChange` once
|
|
80
|
+
// the gesture ends. Cache the latest `brushSelected` payload here, then
|
|
81
|
+
// commit on `brushEnd`.
|
|
82
|
+
const latestBrushedRef = useRef<
|
|
83
|
+
readonly { seriesIndex: number; dataIndex: number[] }[]
|
|
84
|
+
>([])
|
|
85
|
+
|
|
86
|
+
const handleBrushSelected = useCallback((event: unknown) => {
|
|
87
|
+
const params = event as {
|
|
88
|
+
batch?: {
|
|
89
|
+
selected?: { seriesIndex: number; dataIndex: number[] }[]
|
|
90
|
+
}[]
|
|
91
|
+
}
|
|
92
|
+
latestBrushedRef.current = params.batch?.[0]?.selected ?? []
|
|
93
|
+
}, [])
|
|
94
|
+
|
|
95
|
+
const handleBrushEnd = useCallback(() => {
|
|
96
|
+
if (!onSelectionChange) return
|
|
97
|
+
onSelectionChange(keysFromBrush(latestBrushedRef.current))
|
|
98
|
+
}, [onSelectionChange, keysFromBrush])
|
|
99
|
+
|
|
100
|
+
const onEvents = useMemo<Record<string, EchartsEventHandler>>(
|
|
101
|
+
() => ({
|
|
102
|
+
click: handleClick,
|
|
103
|
+
brushSelected: handleBrushSelected,
|
|
104
|
+
brushEnd: handleBrushEnd,
|
|
105
|
+
}),
|
|
106
|
+
[handleClick, handleBrushSelected, handleBrushEnd],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
const wiringSelection = useMemo(
|
|
110
|
+
() => (selection && selection.length > 0 ? selection : null),
|
|
111
|
+
[selection],
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return { onEvents, selection: wiringSelection }
|
|
115
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Chip, type ChipProps } from '@mui/material'
|
|
2
|
+
import type { DeltaSeverity } from './types'
|
|
3
|
+
|
|
4
|
+
export interface DeltaProps {
|
|
5
|
+
/** Numeric magnitude. Used for the default percent label and severity inference. */
|
|
6
|
+
value: number
|
|
7
|
+
/** Pre-formatted label override; skips the default percent formatter. */
|
|
8
|
+
label?: string
|
|
9
|
+
/**
|
|
10
|
+
* Visual treatment. When omitted it's derived from the sign of `value`:
|
|
11
|
+
* `>0 → 'positive'`, `<0 → 'negative'`, `=0 → 'neutral'`.
|
|
12
|
+
*/
|
|
13
|
+
severity?: DeltaSeverity
|
|
14
|
+
/** Override the default `Intl.NumberFormat({style:'percent'})` formatter. */
|
|
15
|
+
format?: (value: number) => string
|
|
16
|
+
ChipProps?: ChipProps
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const defaultPercentFormatter = new Intl.NumberFormat(undefined, {
|
|
20
|
+
style: 'percent',
|
|
21
|
+
signDisplay: 'always',
|
|
22
|
+
maximumFractionDigits: 1,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const SEVERITY_TO_COLOR: Record<DeltaSeverity, ChipProps['color']> = {
|
|
26
|
+
positive: 'success',
|
|
27
|
+
negative: 'error',
|
|
28
|
+
neutral: 'default',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Comparative delta rendered as a small filled chip. Colour is driven by
|
|
33
|
+
* `severity` (or the sign of `value`); content is `label`, the result of
|
|
34
|
+
* `format(value)`, or the default percent format.
|
|
35
|
+
*/
|
|
36
|
+
export function Delta({
|
|
37
|
+
value,
|
|
38
|
+
label,
|
|
39
|
+
severity,
|
|
40
|
+
format,
|
|
41
|
+
ChipProps: chipProps,
|
|
42
|
+
}: DeltaProps) {
|
|
43
|
+
const resolvedSeverity = severity ?? inferSeverity(value)
|
|
44
|
+
const text =
|
|
45
|
+
label ?? (format ? format(value) : defaultPercentFormatter.format(value))
|
|
46
|
+
return (
|
|
47
|
+
<Chip
|
|
48
|
+
size='small'
|
|
49
|
+
color={SEVERITY_TO_COLOR[resolvedSeverity]}
|
|
50
|
+
label={text}
|
|
51
|
+
sx={{ fontWeight: 600 }}
|
|
52
|
+
{...chipProps}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function inferSeverity(value: number): DeltaSeverity {
|
|
58
|
+
if (value > 0) return 'positive'
|
|
59
|
+
if (value < 0) return 'negative'
|
|
60
|
+
return 'neutral'
|
|
61
|
+
}
|