@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,187 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
clearAllWidgetStores,
|
|
4
|
+
createWidgetStore,
|
|
5
|
+
} from './widget-store-registry'
|
|
6
|
+
import type { Transform, WidgetStoreApi } from './types'
|
|
7
|
+
|
|
8
|
+
const t = (
|
|
9
|
+
over: Partial<Transform> & { id: string; fn: Transform['fn']; order: number },
|
|
10
|
+
): Transform => ({
|
|
11
|
+
type: 'data',
|
|
12
|
+
enabled: true,
|
|
13
|
+
...over,
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('pipeline-middleware', () => {
|
|
17
|
+
let store: WidgetStoreApi
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
store = createWidgetStore('pm-test', { data: 1 })
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
clearAllWidgetStores()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('runs the data pipeline when rawData changes', () => {
|
|
28
|
+
store.setState({
|
|
29
|
+
dataTransforms: [
|
|
30
|
+
t({ id: 'd', type: 'data', order: 1, fn: (n) => (n as number) * 2 }),
|
|
31
|
+
],
|
|
32
|
+
})
|
|
33
|
+
store.setState({ rawData: 5 })
|
|
34
|
+
expect(store.getState().data).toBe(10)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('skips the pipeline when neither rawData nor dataTransforms change', () => {
|
|
38
|
+
let runs = 0
|
|
39
|
+
store.setState({
|
|
40
|
+
dataTransforms: [
|
|
41
|
+
t({
|
|
42
|
+
id: 'd',
|
|
43
|
+
type: 'data',
|
|
44
|
+
order: 1,
|
|
45
|
+
fn: (n) => {
|
|
46
|
+
runs++
|
|
47
|
+
return n
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
],
|
|
51
|
+
})
|
|
52
|
+
const baseline = runs
|
|
53
|
+
store.setState({ isLoading: true })
|
|
54
|
+
expect(runs).toBe(baseline)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('sets the error field when a transform throws', () => {
|
|
58
|
+
const bad = t({
|
|
59
|
+
id: 'bad',
|
|
60
|
+
type: 'data',
|
|
61
|
+
order: 1,
|
|
62
|
+
fn: () => {
|
|
63
|
+
throw new Error('pipeline-throw')
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
store.setState({ dataTransforms: [bad], rawData: 1 })
|
|
67
|
+
expect(store.getState().error).toBeInstanceOf(Error)
|
|
68
|
+
expect((store.getState().error as Error).message).toBe('pipeline-throw')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('clears a stale error once a clean pipeline run completes', () => {
|
|
72
|
+
// First run throws and stamps `error` into state.
|
|
73
|
+
const bad = t({
|
|
74
|
+
id: 'bad',
|
|
75
|
+
type: 'data',
|
|
76
|
+
order: 1,
|
|
77
|
+
fn: () => {
|
|
78
|
+
throw new Error('one-shot-throw')
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
store.setState({ dataTransforms: [bad], rawData: 1 })
|
|
82
|
+
expect(store.getState().error).toBeInstanceOf(Error)
|
|
83
|
+
// Next pipeline run completes cleanly — the prior error must be cleared.
|
|
84
|
+
const ok = t({
|
|
85
|
+
id: 'ok',
|
|
86
|
+
type: 'data',
|
|
87
|
+
order: 1,
|
|
88
|
+
fn: (n) => n,
|
|
89
|
+
})
|
|
90
|
+
store.setState({ dataTransforms: [ok], rawData: 2 })
|
|
91
|
+
expect(store.getState().error).toBeUndefined()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('preserves a consumer-set error when a clean pipeline runs (e.g. action mount adds dataTransforms)', () => {
|
|
95
|
+
// Regression: an action like StackToggle mounts and registers a
|
|
96
|
+
// dataTransforms entry; that triggers a pipeline run with no throw.
|
|
97
|
+
// The consumer-supplied error (Provider's `error` prop) must survive.
|
|
98
|
+
const consumerError = new Error('fetch failed')
|
|
99
|
+
store.setState({ error: consumerError })
|
|
100
|
+
// Action mount: a new dataTransforms array reference flows in.
|
|
101
|
+
store.setState({
|
|
102
|
+
dataTransforms: [
|
|
103
|
+
t({
|
|
104
|
+
id: 'noop',
|
|
105
|
+
type: 'data',
|
|
106
|
+
order: 1,
|
|
107
|
+
fn: (n) => n,
|
|
108
|
+
}),
|
|
109
|
+
],
|
|
110
|
+
})
|
|
111
|
+
expect(store.getState().error).toBe(consumerError)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('clears a consumer-set error when the consumer explicitly writes a new one mid-pipeline-run', () => {
|
|
115
|
+
const initial = new Error('first')
|
|
116
|
+
const next = new Error('second')
|
|
117
|
+
store.setState({ error: initial })
|
|
118
|
+
// Consumer writes `error` AND triggers the pipeline in the same call.
|
|
119
|
+
store.setState({
|
|
120
|
+
error: next,
|
|
121
|
+
rawData: 99,
|
|
122
|
+
})
|
|
123
|
+
expect(store.getState().error).toBe(next)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('preserves the first error when multiple transforms throw', () => {
|
|
127
|
+
const a = t({
|
|
128
|
+
id: 'a',
|
|
129
|
+
type: 'data',
|
|
130
|
+
order: 1,
|
|
131
|
+
fn: () => {
|
|
132
|
+
throw new Error('first')
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
const b = t({
|
|
136
|
+
id: 'b',
|
|
137
|
+
type: 'data',
|
|
138
|
+
order: 2,
|
|
139
|
+
fn: () => {
|
|
140
|
+
throw new Error('second')
|
|
141
|
+
},
|
|
142
|
+
})
|
|
143
|
+
store.setState({ dataTransforms: [a, b], rawData: 1 })
|
|
144
|
+
expect((store.getState().error as Error).message).toBe('first')
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('passes incoming non-pipeline updates through unchanged', () => {
|
|
148
|
+
store.setState({ isFetching: true, isLoading: true })
|
|
149
|
+
expect(store.getState().isFetching).toBe(true)
|
|
150
|
+
expect(store.getState().isLoading).toBe(true)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('runs the data pipeline when dataTransforms reference changes', () => {
|
|
154
|
+
const id1 = t({
|
|
155
|
+
id: 'a',
|
|
156
|
+
type: 'data',
|
|
157
|
+
order: 1,
|
|
158
|
+
fn: (n) => (n as number) + 1,
|
|
159
|
+
})
|
|
160
|
+
store.setState({ dataTransforms: [id1] })
|
|
161
|
+
expect(store.getState().data).toBe(2)
|
|
162
|
+
const id2 = t({
|
|
163
|
+
id: 'a',
|
|
164
|
+
type: 'data',
|
|
165
|
+
order: 1,
|
|
166
|
+
fn: (n) => (n as number) + 100,
|
|
167
|
+
})
|
|
168
|
+
store.setState({ dataTransforms: [id2] })
|
|
169
|
+
expect(store.getState().data).toBe(101)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('one set call → one render — atomic raw + derived', () => {
|
|
173
|
+
let renders = 0
|
|
174
|
+
const unsub = store.subscribe(() => {
|
|
175
|
+
renders++
|
|
176
|
+
})
|
|
177
|
+
store.setState({
|
|
178
|
+
rawData: 5,
|
|
179
|
+
dataTransforms: [
|
|
180
|
+
t({ id: 'd', type: 'data', order: 1, fn: (n) => (n as number) * 2 }),
|
|
181
|
+
],
|
|
182
|
+
})
|
|
183
|
+
expect(renders).toBe(1)
|
|
184
|
+
expect(store.getState().data).toBe(10)
|
|
185
|
+
unsub()
|
|
186
|
+
})
|
|
187
|
+
})
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand'
|
|
2
|
+
import type { Transform, WidgetState } from './types'
|
|
3
|
+
import { applyTransforms } from './transforms'
|
|
4
|
+
|
|
5
|
+
type PipelineMiddleware = <
|
|
6
|
+
T extends WidgetState,
|
|
7
|
+
Mps extends [StoreMutatorIdentifier, unknown][] = [],
|
|
8
|
+
Mcs extends [StoreMutatorIdentifier, unknown][] = [],
|
|
9
|
+
>(
|
|
10
|
+
config: StateCreator<T, Mps, Mcs>,
|
|
11
|
+
) => StateCreator<T, Mps, Mcs>
|
|
12
|
+
|
|
13
|
+
type SetFn<T> = StoreApi<T>['setState']
|
|
14
|
+
|
|
15
|
+
// Per-store flag: true iff the current `state.error` was authored by the
|
|
16
|
+
// pipeline (a transform threw) rather than by the consumer (Provider's
|
|
17
|
+
// `error` prop or a direct setState). Lets the middleware clear stale
|
|
18
|
+
// pipeline errors on a subsequent clean run without clobbering errors a
|
|
19
|
+
// consumer set out-of-band.
|
|
20
|
+
const pipelineOwnedError = new WeakSet<StoreApi<WidgetState>>()
|
|
21
|
+
|
|
22
|
+
export const pipelineMiddleware: PipelineMiddleware = ((config) =>
|
|
23
|
+
(set, get, api) => {
|
|
24
|
+
const origSetState = api.setState as SetFn<WidgetState>
|
|
25
|
+
const typedApi = api as StoreApi<WidgetState>
|
|
26
|
+
|
|
27
|
+
const wrap = (delegate: SetFn<WidgetState>): SetFn<WidgetState> =>
|
|
28
|
+
((partial, replace) => {
|
|
29
|
+
const current = (api.getState as () => WidgetState)()
|
|
30
|
+
const incoming =
|
|
31
|
+
typeof partial === 'function'
|
|
32
|
+
? (partial as (s: WidgetState) => Partial<WidgetState>)(current)
|
|
33
|
+
: (partial as Partial<WidgetState>)
|
|
34
|
+
|
|
35
|
+
const has = (key: keyof WidgetState) =>
|
|
36
|
+
Object.prototype.hasOwnProperty.call(incoming, key)
|
|
37
|
+
|
|
38
|
+
const rawDataChanged =
|
|
39
|
+
has('rawData') && !Object.is(incoming.rawData, current.rawData)
|
|
40
|
+
const dataXfChanged =
|
|
41
|
+
has('dataTransforms') &&
|
|
42
|
+
incoming.dataTransforms !== current.dataTransforms
|
|
43
|
+
|
|
44
|
+
if (!rawDataChanged && !dataXfChanged) {
|
|
45
|
+
// Consumer-authored writes that don't trigger the pipeline. If the
|
|
46
|
+
// consumer is explicitly touching `error`, the next pipeline run is
|
|
47
|
+
// no longer responsible for it — drop the pipeline-owned marker.
|
|
48
|
+
if (has('error')) pipelineOwnedError.delete(typedApi)
|
|
49
|
+
return delegate(incoming, replace as false)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const augmented: Partial<WidgetState> = { ...incoming }
|
|
53
|
+
let firstError: unknown = undefined
|
|
54
|
+
const onError = (_id: string, err: Error) => {
|
|
55
|
+
if (firstError === undefined) firstError = err
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const nextRaw = rawDataChanged ? incoming.rawData : current.rawData
|
|
59
|
+
const nextXf: readonly Transform[] = dataXfChanged
|
|
60
|
+
? incoming.dataTransforms!
|
|
61
|
+
: current.dataTransforms
|
|
62
|
+
augmented.data = applyTransforms(nextRaw, nextXf, onError)
|
|
63
|
+
|
|
64
|
+
// Reconcile `error` based on who authored the previous value:
|
|
65
|
+
// - pipeline throw → stamp the new error, mark pipeline-owned.
|
|
66
|
+
// - clean run AND previous error was pipeline-owned → clear it.
|
|
67
|
+
// - clean run AND previous error was consumer-set → leave it.
|
|
68
|
+
// Consumer-authored `error` in `incoming` also wins over the marker
|
|
69
|
+
// (and resets the marker via the early-return branch above).
|
|
70
|
+
if (firstError !== undefined) {
|
|
71
|
+
augmented.error = firstError
|
|
72
|
+
pipelineOwnedError.add(typedApi)
|
|
73
|
+
} else if (pipelineOwnedError.has(typedApi) && !has('error')) {
|
|
74
|
+
augmented.error = undefined
|
|
75
|
+
pipelineOwnedError.delete(typedApi)
|
|
76
|
+
} else if (has('error')) {
|
|
77
|
+
// Consumer set error in the same call that ran the pipeline — honor
|
|
78
|
+
// their write and surrender ownership.
|
|
79
|
+
pipelineOwnedError.delete(typedApi)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return delegate(augmented, replace as false)
|
|
83
|
+
}) as SetFn<WidgetState>
|
|
84
|
+
|
|
85
|
+
// Wrap both the public setState (used by store.setState() callers) and
|
|
86
|
+
// the inner set passed into the state creator (used by actions inside config).
|
|
87
|
+
api.setState = wrap(origSetState) as typeof api.setState
|
|
88
|
+
const wrappedInnerSet = wrap(set as SetFn<WidgetState>)
|
|
89
|
+
|
|
90
|
+
return config(wrappedInnerSet as typeof set, get, api)
|
|
91
|
+
}) as PipelineMiddleware
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { applyTransforms, upsertTransform, removeTransform } from './transforms'
|
|
3
|
+
import type { Transform } from './types'
|
|
4
|
+
|
|
5
|
+
const t = (
|
|
6
|
+
over: Partial<Transform> & { id: string; fn: Transform['fn']; order: number },
|
|
7
|
+
): Transform => ({
|
|
8
|
+
type: 'data',
|
|
9
|
+
enabled: true,
|
|
10
|
+
...over,
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
describe('applyTransforms', () => {
|
|
14
|
+
it('returns input when transforms array is empty', () => {
|
|
15
|
+
expect(applyTransforms({ a: 1 }, [])).toEqual({ a: 1 })
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('applies a single enabled transform', () => {
|
|
19
|
+
const out = applyTransforms(2, [
|
|
20
|
+
t({ id: 'x2', order: 1, fn: (n) => (n as number) * 2 }),
|
|
21
|
+
])
|
|
22
|
+
expect(out).toBe(4)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('chains transforms in order', () => {
|
|
26
|
+
const xs = [
|
|
27
|
+
t({ id: 'a', order: 1, fn: (n) => (n as number) + 1 }),
|
|
28
|
+
t({ id: 'b', order: 2, fn: (n) => (n as number) * 10 }),
|
|
29
|
+
]
|
|
30
|
+
expect(applyTransforms(1, xs)).toBe(20)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('skips disabled transforms', () => {
|
|
34
|
+
const xs = [
|
|
35
|
+
t({ id: 'a', order: 1, fn: (n) => (n as number) + 1 }),
|
|
36
|
+
t({ id: 'b', order: 2, fn: (n) => (n as number) * 10, enabled: false }),
|
|
37
|
+
]
|
|
38
|
+
expect(applyTransforms(1, xs)).toBe(2)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('respects disables map: enabled transform disables another', () => {
|
|
42
|
+
const xs = [
|
|
43
|
+
t({ id: 'a', order: 1, fn: (n) => (n as number) + 1, disables: ['b'] }),
|
|
44
|
+
t({ id: 'b', order: 2, fn: (n) => (n as number) * 10 }),
|
|
45
|
+
]
|
|
46
|
+
expect(applyTransforms(1, xs)).toBe(2)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('does not apply disables when the disabling transform itself is disabled', () => {
|
|
50
|
+
const xs = [
|
|
51
|
+
t({
|
|
52
|
+
id: 'a',
|
|
53
|
+
order: 1,
|
|
54
|
+
fn: (n) => (n as number) + 1,
|
|
55
|
+
disables: ['b'],
|
|
56
|
+
enabled: false,
|
|
57
|
+
}),
|
|
58
|
+
t({ id: 'b', order: 2, fn: (n) => (n as number) * 10 }),
|
|
59
|
+
]
|
|
60
|
+
expect(applyTransforms(1, xs)).toBe(10)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('captures the first error and continues with remaining transforms', () => {
|
|
64
|
+
const errors: { id: string; msg: string }[] = []
|
|
65
|
+
const xs = [
|
|
66
|
+
t({
|
|
67
|
+
id: 'bad',
|
|
68
|
+
order: 1,
|
|
69
|
+
fn: () => {
|
|
70
|
+
throw new Error('boom')
|
|
71
|
+
},
|
|
72
|
+
}),
|
|
73
|
+
t({ id: 'good', order: 2, fn: (n) => (n as number) * 2 }),
|
|
74
|
+
]
|
|
75
|
+
const out = applyTransforms(3, xs, (id, err) =>
|
|
76
|
+
errors.push({ id, msg: err.message }),
|
|
77
|
+
)
|
|
78
|
+
expect(out).toBe(6)
|
|
79
|
+
expect(errors).toEqual([{ id: 'bad', msg: 'boom' }])
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('wraps non-Error throws as Error', () => {
|
|
83
|
+
const errors: Error[] = []
|
|
84
|
+
applyTransforms(
|
|
85
|
+
1,
|
|
86
|
+
[
|
|
87
|
+
t({
|
|
88
|
+
id: 'x',
|
|
89
|
+
order: 1,
|
|
90
|
+
fn: () => {
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/only-throw-error -- exercising non-Error wrap
|
|
92
|
+
throw 'string-throw'
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
(_id, err) => errors.push(err),
|
|
97
|
+
)
|
|
98
|
+
expect(errors[0]).toBeInstanceOf(Error)
|
|
99
|
+
expect(errors[0]?.message).toBe('string-throw')
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
describe('upsertTransform', () => {
|
|
104
|
+
it('inserts new transforms in ascending order', () => {
|
|
105
|
+
const a = t({ id: 'a', order: 10, fn: (n) => n })
|
|
106
|
+
const b = t({ id: 'b', order: 5, fn: (n) => n })
|
|
107
|
+
const c = t({ id: 'c', order: 20, fn: (n) => n })
|
|
108
|
+
const out = upsertTransform(upsertTransform(upsertTransform([], a), b), c)
|
|
109
|
+
expect(out.map((x) => x.id)).toEqual(['b', 'a', 'c'])
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('returns the same array reference when transform is identical', () => {
|
|
113
|
+
const fn = (n: unknown) => n
|
|
114
|
+
const a = t({ id: 'a', order: 1, fn })
|
|
115
|
+
const arr = upsertTransform([], a)
|
|
116
|
+
const next = upsertTransform(arr, t({ id: 'a', order: 1, fn }))
|
|
117
|
+
expect(next).toBe(arr)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('replaces an existing transform when fn changes', () => {
|
|
121
|
+
const a1 = t({ id: 'a', order: 1, fn: (n) => n })
|
|
122
|
+
const a2 = t({ id: 'a', order: 1, fn: (n) => (n as number) + 1 })
|
|
123
|
+
const arr = upsertTransform([], a1)
|
|
124
|
+
const next = upsertTransform(arr, a2)
|
|
125
|
+
expect(next).not.toBe(arr)
|
|
126
|
+
expect(next.find((x) => x.id === 'a')?.fn).toBe(a2.fn)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('reorders when order changes', () => {
|
|
130
|
+
const a = t({ id: 'a', order: 10, fn: (n) => n })
|
|
131
|
+
const b = t({ id: 'b', order: 20, fn: (n) => n })
|
|
132
|
+
const arr = [a, b]
|
|
133
|
+
const next = upsertTransform(arr, t({ id: 'a', order: 30, fn: a.fn }))
|
|
134
|
+
expect(next.map((x) => x.id)).toEqual(['b', 'a'])
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('treats different disables as a structural change', () => {
|
|
138
|
+
const a1 = t({ id: 'a', order: 1, fn: (n) => n, disables: ['b'] })
|
|
139
|
+
const a2 = t({ id: 'a', order: 1, fn: a1.fn, disables: ['c'] })
|
|
140
|
+
const arr = upsertTransform([], a1)
|
|
141
|
+
const next = upsertTransform(arr, a2)
|
|
142
|
+
expect(next).not.toBe(arr)
|
|
143
|
+
expect(next.find((x) => x.id === 'a')?.disables).toEqual(['c'])
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
describe('removeTransform', () => {
|
|
148
|
+
it('removes a transform by id', () => {
|
|
149
|
+
const arr = [
|
|
150
|
+
t({ id: 'a', order: 1, fn: (n) => n }),
|
|
151
|
+
t({ id: 'b', order: 2, fn: (n) => n }),
|
|
152
|
+
]
|
|
153
|
+
const next = removeTransform(arr, 'a')
|
|
154
|
+
expect(next.map((x) => x.id)).toEqual(['b'])
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('returns the same array reference when id is absent', () => {
|
|
158
|
+
const arr = [t({ id: 'a', order: 1, fn: (n) => n })]
|
|
159
|
+
const next = removeTransform(arr, 'missing')
|
|
160
|
+
expect(next).toBe(arr)
|
|
161
|
+
})
|
|
162
|
+
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Transform } from './types'
|
|
2
|
+
|
|
3
|
+
export function applyTransforms(
|
|
4
|
+
input: unknown,
|
|
5
|
+
transforms: readonly Transform[],
|
|
6
|
+
onError?: (id: string, error: Error) => void,
|
|
7
|
+
): unknown {
|
|
8
|
+
const disabledIds = new Set<string>()
|
|
9
|
+
for (const t of transforms) {
|
|
10
|
+
if (t.enabled && t.disables?.length) {
|
|
11
|
+
for (const id of t.disables) disabledIds.add(id)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
let acc: unknown = input
|
|
15
|
+
for (const t of transforms) {
|
|
16
|
+
if (!t.enabled) continue
|
|
17
|
+
if (disabledIds.has(t.id)) continue
|
|
18
|
+
try {
|
|
19
|
+
acc = t.fn(acc)
|
|
20
|
+
} catch (e) {
|
|
21
|
+
const err = e instanceof Error ? e : new Error(String(e))
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
23
|
+
console.warn(`[widgets-v2] Transform "${t.id}" failed:`, err)
|
|
24
|
+
onError?.(t.id, err)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return acc
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function upsertTransform(
|
|
31
|
+
transforms: readonly Transform[],
|
|
32
|
+
next: Transform,
|
|
33
|
+
): readonly Transform[] {
|
|
34
|
+
const existing = transforms.find((t) => t.id === next.id)
|
|
35
|
+
if (
|
|
36
|
+
existing?.order === next.order &&
|
|
37
|
+
existing?.enabled === next.enabled &&
|
|
38
|
+
existing?.fn === next.fn &&
|
|
39
|
+
existing?.type === next.type &&
|
|
40
|
+
sameStringArray(existing?.disables, next.disables) &&
|
|
41
|
+
sameStringArray(existing?.replaceMergeKeys, next.replaceMergeKeys)
|
|
42
|
+
) {
|
|
43
|
+
return transforms
|
|
44
|
+
}
|
|
45
|
+
const filtered = transforms.filter((t) => t.id !== next.id)
|
|
46
|
+
const idx = filtered.findIndex((t) => t.order > next.order)
|
|
47
|
+
const out = filtered.slice()
|
|
48
|
+
out.splice(idx === -1 ? out.length : idx, 0, next)
|
|
49
|
+
return out
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function removeTransform(
|
|
53
|
+
transforms: readonly Transform[],
|
|
54
|
+
id: string,
|
|
55
|
+
): readonly Transform[] {
|
|
56
|
+
if (!transforms.some((t) => t.id === id)) return transforms
|
|
57
|
+
return transforms.filter((t) => t.id !== id)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function sameStringArray(
|
|
61
|
+
a?: readonly string[],
|
|
62
|
+
b?: readonly string[],
|
|
63
|
+
): boolean {
|
|
64
|
+
if (a === b) return true
|
|
65
|
+
if (!a) return !b?.length
|
|
66
|
+
if (!b) return !a.length
|
|
67
|
+
if (a.length !== b.length) return false
|
|
68
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { StoreApi } from 'zustand'
|
|
2
|
+
|
|
3
|
+
export type TransformType = 'data' | 'config'
|
|
4
|
+
|
|
5
|
+
export interface TransformDescriptor {
|
|
6
|
+
id: string
|
|
7
|
+
type: TransformType
|
|
8
|
+
order: number
|
|
9
|
+
disables?: string[]
|
|
10
|
+
replaceMergeKeys?: string[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type TransformFn = (input: unknown) => unknown
|
|
14
|
+
|
|
15
|
+
export interface Transform extends TransformDescriptor {
|
|
16
|
+
fn: TransformFn
|
|
17
|
+
enabled: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface TransformPair {
|
|
21
|
+
descriptor: TransformDescriptor
|
|
22
|
+
fn: TransformFn
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface WidgetState {
|
|
26
|
+
rawData: unknown
|
|
27
|
+
data: unknown
|
|
28
|
+
|
|
29
|
+
dataTransforms: readonly Transform[]
|
|
30
|
+
configTransforms: readonly Transform[]
|
|
31
|
+
|
|
32
|
+
transformStates: Record<string, { enabled: boolean; [k: string]: unknown }>
|
|
33
|
+
|
|
34
|
+
isLoading: boolean
|
|
35
|
+
isFetching: boolean
|
|
36
|
+
error: unknown
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Original formatter as supplied by the consumer (Provider's `formatter`
|
|
40
|
+
* prop). Always live-synced — never overridden by actions. Actions that need
|
|
41
|
+
* to display a different formatter (e.g. {@link RelativeData}'s percent
|
|
42
|
+
* formatter) should write to {@link WidgetState.formatter} and read this
|
|
43
|
+
* field when restoring the absolute view.
|
|
44
|
+
*/
|
|
45
|
+
rawFormatter?: (value: number) => string
|
|
46
|
+
/**
|
|
47
|
+
* Active formatter — what consumer code (tooltips, axis labels, legends,
|
|
48
|
+
* etc.) reads. Defaults to {@link WidgetState.rawFormatter}; actions may
|
|
49
|
+
* override it temporarily and restore it from `rawFormatter` later.
|
|
50
|
+
*/
|
|
51
|
+
formatter?: (value: number) => string
|
|
52
|
+
labelFormatter?: (value: string | number) => string | number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface WidgetInit {
|
|
56
|
+
data: unknown
|
|
57
|
+
isLoading?: boolean
|
|
58
|
+
isFetching?: boolean
|
|
59
|
+
error?: unknown
|
|
60
|
+
formatter?: (value: number) => string
|
|
61
|
+
labelFormatter?: (value: string | number) => string | number
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type WidgetStoreApi = StoreApi<WidgetState>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
3
|
+
import { act, render } from '@testing-library/react'
|
|
4
|
+
import type { ECharts } from 'echarts'
|
|
5
|
+
import { useEchartInstance } from './use-echart-instance'
|
|
6
|
+
import {
|
|
7
|
+
clearAllWidgetStores,
|
|
8
|
+
setEchartInstance,
|
|
9
|
+
} from './widget-store-registry'
|
|
10
|
+
|
|
11
|
+
const captured: { value: ECharts | null; renders: number } = {
|
|
12
|
+
value: null,
|
|
13
|
+
renders: 0,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function Probe({ id }: { id: string }) {
|
|
17
|
+
const chart = useEchartInstance(id)
|
|
18
|
+
// Capture in an effect so the React Compiler doesn't flag the
|
|
19
|
+
// outside-component mutations during render.
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
captured.value = chart
|
|
22
|
+
captured.renders += 1
|
|
23
|
+
})
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
clearAllWidgetStores()
|
|
29
|
+
captured.value = null
|
|
30
|
+
captured.renders = 0
|
|
31
|
+
})
|
|
32
|
+
afterEach(() => clearAllWidgetStores())
|
|
33
|
+
|
|
34
|
+
function makeChart(): ECharts {
|
|
35
|
+
return {} as unknown as ECharts
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe('useEchartInstance', () => {
|
|
39
|
+
it('returns null when no instance is registered', () => {
|
|
40
|
+
render(<Probe id='h1' />)
|
|
41
|
+
expect(captured.value).toBeNull()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('re-renders the consumer when the instance arrives', () => {
|
|
45
|
+
render(<Probe id='h2' />)
|
|
46
|
+
const initialRenders = captured.renders
|
|
47
|
+
const chart = makeChart()
|
|
48
|
+
act(() => setEchartInstance('h2', chart))
|
|
49
|
+
expect(captured.value).toBe(chart)
|
|
50
|
+
expect(captured.renders).toBeGreaterThan(initialRenders)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('re-renders again when the instance changes', () => {
|
|
54
|
+
render(<Probe id='h3' />)
|
|
55
|
+
const a = makeChart()
|
|
56
|
+
const b = makeChart()
|
|
57
|
+
act(() => setEchartInstance('h3', a))
|
|
58
|
+
expect(captured.value).toBe(a)
|
|
59
|
+
act(() => setEchartInstance('h3', b))
|
|
60
|
+
expect(captured.value).toBe(b)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('re-renders with null when the instance is cleared', () => {
|
|
64
|
+
render(<Probe id='h4' />)
|
|
65
|
+
act(() => setEchartInstance('h4', makeChart()))
|
|
66
|
+
expect(captured.value).not.toBeNull()
|
|
67
|
+
act(() => setEchartInstance('h4', null))
|
|
68
|
+
expect(captured.value).toBeNull()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('isolates ids', () => {
|
|
72
|
+
const latest: { a: ECharts | null; b: ECharts | null } = {
|
|
73
|
+
a: null,
|
|
74
|
+
b: null,
|
|
75
|
+
}
|
|
76
|
+
function ProbeMulti() {
|
|
77
|
+
const a = useEchartInstance('h5-a')
|
|
78
|
+
const b = useEchartInstance('h5-b')
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
latest.a = a
|
|
81
|
+
latest.b = b
|
|
82
|
+
})
|
|
83
|
+
return null
|
|
84
|
+
}
|
|
85
|
+
render(<ProbeMulti />)
|
|
86
|
+
const aChart = makeChart()
|
|
87
|
+
act(() => setEchartInstance('h5-a', aChart))
|
|
88
|
+
expect(latest.a).toBe(aChart)
|
|
89
|
+
expect(latest.b).toBeNull()
|
|
90
|
+
})
|
|
91
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react'
|
|
2
|
+
import type { ECharts } from 'echarts'
|
|
3
|
+
import {
|
|
4
|
+
getEchartInstance,
|
|
5
|
+
subscribeEchartInstance,
|
|
6
|
+
} from './widget-store-registry'
|
|
7
|
+
|
|
8
|
+
const SSR_SNAPSHOT = (): ECharts | null => null
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reactive read of the live ECharts instance for a widget. Returns
|
|
12
|
+
* `null` before the `Widget.Echart` bridge has mounted (or after it's
|
|
13
|
+
* disposed); the consumer re-renders when the instance arrives /
|
|
14
|
+
* departs / changes.
|
|
15
|
+
*
|
|
16
|
+
* Wraps {@link subscribeEchartInstance} via `useSyncExternalStore`, so
|
|
17
|
+
* actions can use it inside an effect's deps array to react to chart
|
|
18
|
+
* lifecycle events without polling. Required for actions like
|
|
19
|
+
* `BrushToggle` whose effect needs to dispatch `takeGlobalCursor` the
|
|
20
|
+
* moment the chart exists, then re-dispatch on every `'finished'`
|
|
21
|
+
* event.
|
|
22
|
+
*/
|
|
23
|
+
export function useEchartInstance(id: string): ECharts | null {
|
|
24
|
+
return useSyncExternalStore(
|
|
25
|
+
(cb) => subscribeEchartInstance(id, cb),
|
|
26
|
+
() => getEchartInstance(id),
|
|
27
|
+
SSR_SNAPSHOT,
|
|
28
|
+
)
|
|
29
|
+
}
|