@carto/ps-react-ui 4.7.0 → 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/actions.js +688 -668
- package/dist/widgets/actions.js.map +1 -1
- package/dist/widgets/bar.js +14 -13
- package/dist/widgets/bar.js.map +1 -1
- package/dist/widgets/histogram.js +38 -37
- 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-overlay.tsx +24 -2
- 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/histogram/config.ts +1 -3
- 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,151 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { createPercentFormatter, toRelativeData } from './transforms'
|
|
3
|
+
|
|
4
|
+
describe('toRelativeData (default — named-value shape)', () => {
|
|
5
|
+
it('rewrites each datum value as its share of the series total in 0-100', () => {
|
|
6
|
+
const input = [
|
|
7
|
+
[
|
|
8
|
+
{ name: 'a', value: 25 },
|
|
9
|
+
{ name: 'b', value: 75 },
|
|
10
|
+
],
|
|
11
|
+
]
|
|
12
|
+
expect(toRelativeData(input)).toEqual([
|
|
13
|
+
[
|
|
14
|
+
{ name: 'a', value: 25 },
|
|
15
|
+
{ name: 'b', value: 75 },
|
|
16
|
+
],
|
|
17
|
+
])
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('handles non-100 totals (50/200 = 25%)', () => {
|
|
21
|
+
const input = [
|
|
22
|
+
[
|
|
23
|
+
{ name: 'a', value: 50 },
|
|
24
|
+
{ name: 'b', value: 150 },
|
|
25
|
+
],
|
|
26
|
+
]
|
|
27
|
+
expect(toRelativeData(input)).toEqual([
|
|
28
|
+
[
|
|
29
|
+
{ name: 'a', value: 25 },
|
|
30
|
+
{ name: 'b', value: 75 },
|
|
31
|
+
],
|
|
32
|
+
])
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('handles multiple series independently', () => {
|
|
36
|
+
const input = [
|
|
37
|
+
[{ name: 'x', value: 10 }],
|
|
38
|
+
[
|
|
39
|
+
{ name: 'x', value: 50 },
|
|
40
|
+
{ name: 'y', value: 50 },
|
|
41
|
+
],
|
|
42
|
+
]
|
|
43
|
+
const out = toRelativeData(input) as { value: number }[][]
|
|
44
|
+
expect(out[0]?.[0]?.value).toBe(100)
|
|
45
|
+
expect(out[1]?.[0]?.value).toBe(50)
|
|
46
|
+
expect(out[1]?.[1]?.value).toBe(50)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('preserves extra fields on each datum', () => {
|
|
50
|
+
const input = [[{ name: 'a', value: 10, color: '#fff' }]]
|
|
51
|
+
expect(toRelativeData(input)).toEqual([
|
|
52
|
+
[{ name: 'a', value: 100, color: '#fff' }],
|
|
53
|
+
])
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('returns the series unchanged when total is zero', () => {
|
|
57
|
+
const input = [
|
|
58
|
+
[
|
|
59
|
+
{ name: 'a', value: 0 },
|
|
60
|
+
{ name: 'b', value: 0 },
|
|
61
|
+
],
|
|
62
|
+
]
|
|
63
|
+
expect(toRelativeData(input)).toEqual(input)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('produces signed share-of-magnitude percentages for mixed-sign series', () => {
|
|
67
|
+
const input = [
|
|
68
|
+
[
|
|
69
|
+
{ name: 'a', value: 1000 },
|
|
70
|
+
{ name: 'b', value: -990 },
|
|
71
|
+
],
|
|
72
|
+
]
|
|
73
|
+
const out = toRelativeData(input) as { value: number }[][]
|
|
74
|
+
// Denominator is 1000 + 990 = 1990, so 1000 / 1990 ≈ 50.25%
|
|
75
|
+
expect(out[0]?.[0]?.value).toBeCloseTo(50.25126, 4)
|
|
76
|
+
expect(out[0]?.[1]?.value).toBeCloseTo(-49.74874, 4)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('works for all-negative series (signed shares sum to -100)', () => {
|
|
80
|
+
const input = [
|
|
81
|
+
[
|
|
82
|
+
{ name: 'a', value: -100 },
|
|
83
|
+
{ name: 'b', value: -200 },
|
|
84
|
+
],
|
|
85
|
+
]
|
|
86
|
+
const out = toRelativeData(input) as { value: number }[][]
|
|
87
|
+
expect(out[0]?.[0]?.value).toBeCloseTo(-33.333, 2)
|
|
88
|
+
expect(out[0]?.[1]?.value).toBeCloseTo(-66.667, 2)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('returns the input unchanged when shape does not match named-value', () => {
|
|
92
|
+
expect(toRelativeData(null)).toBe(null)
|
|
93
|
+
expect(toRelativeData('not an array')).toBe('not an array')
|
|
94
|
+
// A top-level array whose entries are neither arrays-of-named-value
|
|
95
|
+
// nor matching the predicate falls through. Each series that isn't
|
|
96
|
+
// a named-value array is returned as-is — that's how widgets with
|
|
97
|
+
// a different shape (and their own transform) avoid double-running
|
|
98
|
+
// through this one.
|
|
99
|
+
expect(toRelativeData([42])).toEqual([42])
|
|
100
|
+
expect(toRelativeData([[1, 2, 3]])).toEqual([[1, 2, 3]])
|
|
101
|
+
expect(
|
|
102
|
+
toRelativeData([
|
|
103
|
+
[
|
|
104
|
+
[1, 10],
|
|
105
|
+
[2, 20],
|
|
106
|
+
],
|
|
107
|
+
]),
|
|
108
|
+
).toEqual([
|
|
109
|
+
[
|
|
110
|
+
[1, 10],
|
|
111
|
+
[2, 20],
|
|
112
|
+
],
|
|
113
|
+
])
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
describe('createPercentFormatter', () => {
|
|
118
|
+
it('formats 0-100 input as percentages via Intl.NumberFormat', () => {
|
|
119
|
+
const fmt = createPercentFormatter('en-US')
|
|
120
|
+
// minimumFractionDigits: 0, maximumFractionDigits: 2 — integers render
|
|
121
|
+
// without decimals, fractions get up to two decimal places.
|
|
122
|
+
expect(fmt(50)).toBe('50%')
|
|
123
|
+
expect(fmt(2.5)).toBe('2.5%')
|
|
124
|
+
expect(fmt(100)).toBe('100%')
|
|
125
|
+
expect(fmt(12.345)).toBe('12.35%')
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('respects the provided locale (en-US uses dot, es-ES uses comma)', () => {
|
|
129
|
+
const en = createPercentFormatter('en-US')
|
|
130
|
+
const es = createPercentFormatter('es-ES')
|
|
131
|
+
expect(en(12.3)).toContain('12.3')
|
|
132
|
+
// Spanish locale uses comma as decimal separator. Format strings vary by
|
|
133
|
+
// ICU version (some emit narrow no-break space before "%"); assert on the
|
|
134
|
+
// decimal separator and the digits rather than the entire output.
|
|
135
|
+
const esOut = es(12.3)
|
|
136
|
+
expect(esOut).toContain('12,3')
|
|
137
|
+
expect(esOut).toContain('%')
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('passes through non-finite values as their string form', () => {
|
|
141
|
+
const fmt = createPercentFormatter('en-US')
|
|
142
|
+
expect(fmt(NaN)).toBe('NaN')
|
|
143
|
+
expect(fmt(Infinity)).toBe('Infinity')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('falls back to runtime default locale when none is provided', () => {
|
|
147
|
+
const fmt = createPercentFormatter()
|
|
148
|
+
// Whatever locale the runtime uses, 50 should produce a string ending in '%'
|
|
149
|
+
expect(fmt(50)).toMatch(/%$/)
|
|
150
|
+
})
|
|
151
|
+
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default data-side transform for `RelativeData`: rewrite each
|
|
3
|
+
* `{ name, value }` datum's `value` to its share of the series total
|
|
4
|
+
* expressed as 0–100 (matches v1's range). The companion percent
|
|
5
|
+
* formatter divides by 100 so it can call `Intl.NumberFormat` with
|
|
6
|
+
* `style: 'percent'`.
|
|
7
|
+
*
|
|
8
|
+
* Used by widgets whose series are arrays of `{ name, value }`
|
|
9
|
+
* objects — bar, pie, timeseries, category. Widgets with a different
|
|
10
|
+
* data shape pass their own transform via
|
|
11
|
+
* `<RelativeData transform={...} />`; see `widgets-v2/histogram` and
|
|
12
|
+
* `widgets-v2/scatterplot` for in-tree examples.
|
|
13
|
+
*
|
|
14
|
+
* The denominator is the sum of |value| across the series so mixed-sign
|
|
15
|
+
* series (e.g. cashflow with inflows + outflows) produce sane signed
|
|
16
|
+
* shares-of-magnitude. A series whose total magnitude is zero (all-zero
|
|
17
|
+
* or empty input) is returned unchanged so a stalled or empty data set
|
|
18
|
+
* doesn't show misleading 0% values. Series whose shape doesn't match
|
|
19
|
+
* the named-value pattern fall through untouched.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
interface NamedValue {
|
|
23
|
+
name: unknown
|
|
24
|
+
value: number
|
|
25
|
+
[k: string]: unknown
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isNamedValueArray(v: unknown): v is NamedValue[] {
|
|
29
|
+
if (!Array.isArray(v)) return false
|
|
30
|
+
return v.every(
|
|
31
|
+
(item) =>
|
|
32
|
+
item != null &&
|
|
33
|
+
typeof item === 'object' &&
|
|
34
|
+
'value' in item &&
|
|
35
|
+
typeof (item as { value: unknown }).value === 'number',
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const toRelativeData = (input: unknown): unknown => {
|
|
40
|
+
if (!Array.isArray(input)) return input
|
|
41
|
+
return input.map((series: unknown): unknown => {
|
|
42
|
+
if (!isNamedValueArray(series)) return series
|
|
43
|
+
const total = series.reduce((acc, d) => acc + Math.abs(d.value), 0)
|
|
44
|
+
if (total <= 0) return series
|
|
45
|
+
return series.map((d) => ({ ...d, value: (d.value / total) * 100 }))
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Build a percent formatter using `Intl.NumberFormat`. The returned function
|
|
51
|
+
* expects values in the 0–100 range (output of {@link toRelativeData}) and
|
|
52
|
+
* divides by 100 internally before calling `style: 'percent'`.
|
|
53
|
+
*
|
|
54
|
+
* Locale: passed straight to `Intl.NumberFormat`. Falls back to the runtime
|
|
55
|
+
* default when omitted.
|
|
56
|
+
*/
|
|
57
|
+
export function createPercentFormatter(
|
|
58
|
+
locale?: string,
|
|
59
|
+
): (value: number) => string {
|
|
60
|
+
const fmt = new Intl.NumberFormat(locale, {
|
|
61
|
+
style: 'percent',
|
|
62
|
+
minimumFractionDigits: 0,
|
|
63
|
+
maximumFractionDigits: 2,
|
|
64
|
+
})
|
|
65
|
+
return (value: number) => {
|
|
66
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
67
|
+
return String(value)
|
|
68
|
+
return fmt.format(value / 100)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filters a 2D series of `{name, ...}` records by case-insensitive substring on
|
|
3
|
+
* the `name` field. Keeps the dataset shape (one inner array per series).
|
|
4
|
+
* Used by the Searcher action's data transform.
|
|
5
|
+
*/
|
|
6
|
+
export function filterBySearchText(input: unknown, search: string): unknown {
|
|
7
|
+
if (!search) return input
|
|
8
|
+
const needle = search.toLowerCase()
|
|
9
|
+
if (!Array.isArray(input)) return input
|
|
10
|
+
return input.map((series: unknown): unknown => {
|
|
11
|
+
if (!Array.isArray(series)) return series
|
|
12
|
+
return series.filter((item: unknown) => {
|
|
13
|
+
if (item == null) return false
|
|
14
|
+
if (typeof item === 'object' && 'name' in item) {
|
|
15
|
+
const rawName = (item as { name: unknown }).name
|
|
16
|
+
const name = rawName == null ? '' : stringifyPrimitive(rawName)
|
|
17
|
+
return name.toLowerCase().includes(needle)
|
|
18
|
+
}
|
|
19
|
+
return stringifyPrimitive(item).toLowerCase().includes(needle)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function stringifyPrimitive(v: unknown): string {
|
|
25
|
+
if (typeof v === 'string') return v
|
|
26
|
+
if (typeof v === 'number' || typeof v === 'boolean') return String(v)
|
|
27
|
+
return ''
|
|
28
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { Searcher, type SearcherProps } from './searcher'
|
|
2
|
+
export {
|
|
3
|
+
SearcherToggle,
|
|
4
|
+
setSearcherText,
|
|
5
|
+
type SearcherToggleProps,
|
|
6
|
+
} from './searcher-toggle'
|
|
7
|
+
export { filterBySearchText } from './filter'
|
|
8
|
+
export { DEFAULT_SEARCHER_LABELS, type SearcherLabels } from './labels'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface SearcherLabels {
|
|
2
|
+
toggle: string
|
|
3
|
+
placeholder: string
|
|
4
|
+
clearAriaLabel: string
|
|
5
|
+
noResults: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_SEARCHER_LABELS: SearcherLabels = {
|
|
9
|
+
toggle: 'Search',
|
|
10
|
+
placeholder: 'Search…',
|
|
11
|
+
clearAriaLabel: 'Clear search',
|
|
12
|
+
noResults: 'No matches.',
|
|
13
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useCallback, type ComponentType } from 'react'
|
|
2
|
+
import { IconButton, type SvgIconProps } from '@mui/material'
|
|
3
|
+
import SearchIcon from '@mui/icons-material/Search'
|
|
4
|
+
import { Tooltip } from '../../../components'
|
|
5
|
+
import {
|
|
6
|
+
getWidgetStore,
|
|
7
|
+
useSingleTransform,
|
|
8
|
+
useWidget,
|
|
9
|
+
useWidgetId,
|
|
10
|
+
} from '../../stores'
|
|
11
|
+
import { filterBySearchText } from './filter'
|
|
12
|
+
import { DEFAULT_SEARCHER_LABELS, type SearcherLabels } from './labels'
|
|
13
|
+
import { styles } from './style'
|
|
14
|
+
|
|
15
|
+
const SEARCHER_DESCRIPTOR = {
|
|
16
|
+
id: 'searcher',
|
|
17
|
+
type: 'data' as const,
|
|
18
|
+
order: 20,
|
|
19
|
+
disables: ['lock-selection'],
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SearcherToggleProps {
|
|
23
|
+
labels?: Partial<SearcherLabels>
|
|
24
|
+
icon?: ComponentType<SvgIconProps>
|
|
25
|
+
iconProps?: SvgIconProps
|
|
26
|
+
/**
|
|
27
|
+
* Whether the searcher transform is enabled on first mount. Defaults
|
|
28
|
+
* to `false` so the toggle renders un-pressed and the
|
|
29
|
+
* `filterBySearchText` transform stays dormant until the user clicks
|
|
30
|
+
* it. Set to `true` for search-first widgets where the input is the
|
|
31
|
+
* primary affordance.
|
|
32
|
+
*/
|
|
33
|
+
initialEnabled?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function SearcherToggle({
|
|
37
|
+
labels,
|
|
38
|
+
icon: Icon = SearchIcon,
|
|
39
|
+
iconProps,
|
|
40
|
+
initialEnabled = false,
|
|
41
|
+
}: SearcherToggleProps) {
|
|
42
|
+
const id = useWidgetId()
|
|
43
|
+
const resolved = { ...DEFAULT_SEARCHER_LABELS, ...labels }
|
|
44
|
+
const text = useWidget(
|
|
45
|
+
id,
|
|
46
|
+
(s) => (s.transformStates.searcher?.searchText as string | undefined) ?? '',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
// The transform fn closes over `text`. Memoize via useCallback so identity
|
|
50
|
+
// only changes when text changes, allowing useTransform to re-register.
|
|
51
|
+
const fn = useCallback(
|
|
52
|
+
(data: unknown) => filterBySearchText(data, text),
|
|
53
|
+
[text],
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const { enabled, toggle } = useSingleTransform(id, SEARCHER_DESCRIPTOR, fn, {
|
|
57
|
+
initialEnabled,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<Tooltip title={resolved.toggle}>
|
|
62
|
+
<IconButton
|
|
63
|
+
size='small'
|
|
64
|
+
aria-label={resolved.toggle}
|
|
65
|
+
aria-pressed={enabled}
|
|
66
|
+
onClick={toggle}
|
|
67
|
+
sx={{ ...styles.toggle, ...(enabled && styles.toggleActive) }}
|
|
68
|
+
>
|
|
69
|
+
<Icon fontSize='small' {...iconProps} />
|
|
70
|
+
</IconButton>
|
|
71
|
+
</Tooltip>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Imperatively writes the search text into the widget store. Used by the
|
|
77
|
+
* Searcher input to update text inside transformStates without going through
|
|
78
|
+
* a re-rendered React subscription.
|
|
79
|
+
*/
|
|
80
|
+
export function setSearcherText(widgetId: string, value: string): void {
|
|
81
|
+
getWidgetStore(widgetId).setState((s) => ({
|
|
82
|
+
transformStates: {
|
|
83
|
+
...s.transformStates,
|
|
84
|
+
searcher: {
|
|
85
|
+
enabled: s.transformStates.searcher?.enabled ?? false,
|
|
86
|
+
...s.transformStates.searcher,
|
|
87
|
+
searchText: value,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
}))
|
|
91
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
2
|
+
import { fireEvent, render, screen, act } from '@testing-library/react'
|
|
3
|
+
import { Provider } from '../../provider/widget-provider'
|
|
4
|
+
import { clearAllWidgetStores, getWidgetStore } from '../../stores'
|
|
5
|
+
import { Searcher } from './searcher'
|
|
6
|
+
import { SearcherToggle } from './searcher-toggle'
|
|
7
|
+
|
|
8
|
+
beforeEach(() => clearAllWidgetStores())
|
|
9
|
+
afterEach(() => clearAllWidgetStores())
|
|
10
|
+
|
|
11
|
+
const DATA = [
|
|
12
|
+
[
|
|
13
|
+
{ name: 'apple', value: 1 },
|
|
14
|
+
{ name: 'banana', value: 2 },
|
|
15
|
+
{ name: 'cherry', value: 3 },
|
|
16
|
+
],
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
describe('<Searcher> + <SearcherToggle>', () => {
|
|
20
|
+
it('toggle defaults off — aria-pressed=false and input hidden', () => {
|
|
21
|
+
render(
|
|
22
|
+
<Provider id='sr1' data={DATA}>
|
|
23
|
+
<SearcherToggle />
|
|
24
|
+
<Searcher />
|
|
25
|
+
</Provider>,
|
|
26
|
+
)
|
|
27
|
+
const btn = screen.getByRole('button', { name: 'Search' })
|
|
28
|
+
expect(btn.getAttribute('aria-pressed')).toBe('false')
|
|
29
|
+
expect(screen.queryByPlaceholderText('Search…')).toBeNull()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('initialEnabled=true opts into the legacy "search-first" behavior', () => {
|
|
33
|
+
render(
|
|
34
|
+
<Provider id='sr1b' data={DATA}>
|
|
35
|
+
<SearcherToggle initialEnabled />
|
|
36
|
+
<Searcher />
|
|
37
|
+
</Provider>,
|
|
38
|
+
)
|
|
39
|
+
const btn = screen.getByRole('button', { name: 'Search' })
|
|
40
|
+
expect(btn.getAttribute('aria-pressed')).toBe('true')
|
|
41
|
+
expect(screen.getByPlaceholderText('Search…')).toBeTruthy()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('clicking the toggle reveals the input and flips aria-pressed', () => {
|
|
45
|
+
render(
|
|
46
|
+
<Provider id='sr2' data={DATA}>
|
|
47
|
+
<SearcherToggle />
|
|
48
|
+
<Searcher />
|
|
49
|
+
</Provider>,
|
|
50
|
+
)
|
|
51
|
+
fireEvent.click(screen.getByRole('button', { name: 'Search' }))
|
|
52
|
+
expect(screen.getByPlaceholderText('Search…')).toBeTruthy()
|
|
53
|
+
expect(
|
|
54
|
+
screen
|
|
55
|
+
.getByRole('button', { name: 'Search' })
|
|
56
|
+
.getAttribute('aria-pressed'),
|
|
57
|
+
).toBe('true')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('debounces input changes; after the timer fires the searchText is committed and the data is filtered', () => {
|
|
61
|
+
vi.useFakeTimers({ shouldAdvanceTime: true })
|
|
62
|
+
try {
|
|
63
|
+
render(
|
|
64
|
+
<Provider id='sr3' data={DATA}>
|
|
65
|
+
<SearcherToggle initialEnabled />
|
|
66
|
+
<Searcher debounceMs={100} />
|
|
67
|
+
</Provider>,
|
|
68
|
+
)
|
|
69
|
+
// `initialEnabled` opens the input straight away — no click needed.
|
|
70
|
+
const input = screen.getByPlaceholderText('Search…')
|
|
71
|
+
fireEvent.change(input, { target: { value: 'app' } })
|
|
72
|
+
// Pre-debounce: store still has no committed searchText.
|
|
73
|
+
expect(
|
|
74
|
+
getWidgetStore('sr3').getState().transformStates.searcher?.searchText,
|
|
75
|
+
).toBeUndefined()
|
|
76
|
+
|
|
77
|
+
act(() => {
|
|
78
|
+
vi.advanceTimersByTime(120)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
expect(
|
|
82
|
+
getWidgetStore('sr3').getState().transformStates.searcher?.searchText,
|
|
83
|
+
).toBe('app')
|
|
84
|
+
const filtered = getWidgetStore('sr3').getState().data as {
|
|
85
|
+
name: string
|
|
86
|
+
}[][]
|
|
87
|
+
expect(filtered.flat().map((r) => r.name)).toEqual(['apple'])
|
|
88
|
+
} finally {
|
|
89
|
+
vi.useRealTimers()
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
})
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from 'react'
|
|
2
|
+
import { IconButton, InputAdornment, TextField } from '@mui/material'
|
|
3
|
+
import SearchIcon from '@mui/icons-material/Search'
|
|
4
|
+
import ClearIcon from '@mui/icons-material/Clear'
|
|
5
|
+
import { debounce } from '@carto/ps-utils'
|
|
6
|
+
import { getWidgetStore, useWidget, useWidgetId } from '../../stores'
|
|
7
|
+
import { setSearcherText } from './searcher-toggle'
|
|
8
|
+
import { DEFAULT_SEARCHER_LABELS, type SearcherLabels } from './labels'
|
|
9
|
+
import { styles } from './style'
|
|
10
|
+
|
|
11
|
+
export interface SearcherProps {
|
|
12
|
+
labels?: Partial<SearcherLabels>
|
|
13
|
+
/** Debounce delay before the input value is written to the widget store. */
|
|
14
|
+
debounceMs?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const DEFAULT_DEBOUNCE = 300
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Renders only when the matching `<SearcherToggle />` is enabled — drives the
|
|
21
|
+
* `transformStates['searcher'].searchText` field via a debounced setter.
|
|
22
|
+
*/
|
|
23
|
+
export function Searcher({
|
|
24
|
+
labels,
|
|
25
|
+
debounceMs = DEFAULT_DEBOUNCE,
|
|
26
|
+
}: SearcherProps) {
|
|
27
|
+
const id = useWidgetId()
|
|
28
|
+
const resolved = { ...DEFAULT_SEARCHER_LABELS, ...labels }
|
|
29
|
+
const enabled = useWidget(
|
|
30
|
+
id,
|
|
31
|
+
(s) => s.transformStates.searcher?.enabled ?? false,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const inputRef = useRef<HTMLInputElement | null>(null)
|
|
35
|
+
|
|
36
|
+
// Hydrate from the store so re-toggling the input preserves any prior text.
|
|
37
|
+
const [local, setLocal] = useState<string>(
|
|
38
|
+
() =>
|
|
39
|
+
(getWidgetStore(id).getState().transformStates.searcher?.searchText as
|
|
40
|
+
| string
|
|
41
|
+
| undefined) ?? '',
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const debouncedWrite = useMemo(
|
|
45
|
+
() =>
|
|
46
|
+
debounce(
|
|
47
|
+
(value: unknown) => setSearcherText(id, value as string),
|
|
48
|
+
debounceMs,
|
|
49
|
+
),
|
|
50
|
+
[id, debounceMs],
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const handleSearchTextChange = useCallback(
|
|
54
|
+
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
55
|
+
const value = e.target.value
|
|
56
|
+
setLocal(value)
|
|
57
|
+
debouncedWrite(value)
|
|
58
|
+
},
|
|
59
|
+
[debouncedWrite],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
const handleClear = useCallback(() => {
|
|
63
|
+
setLocal('')
|
|
64
|
+
setSearcherText(id, '')
|
|
65
|
+
// Re-arm the debounced timer with '' so any pending stale write resolves
|
|
66
|
+
// to the cleared value rather than re-applying the previous text.
|
|
67
|
+
debouncedWrite('')
|
|
68
|
+
inputRef.current?.focus()
|
|
69
|
+
}, [id, debouncedWrite])
|
|
70
|
+
|
|
71
|
+
if (!enabled) return null
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<TextField
|
|
75
|
+
inputRef={inputRef}
|
|
76
|
+
size='small'
|
|
77
|
+
fullWidth
|
|
78
|
+
variant='filled'
|
|
79
|
+
placeholder={resolved.placeholder}
|
|
80
|
+
value={local}
|
|
81
|
+
onChange={handleSearchTextChange}
|
|
82
|
+
// The Searcher only mounts when the user explicitly toggles the
|
|
83
|
+
// SearcherToggle action — focusing the input on mount matches user
|
|
84
|
+
// intent, so the jsx-a11y/no-autofocus warning is the false-positive
|
|
85
|
+
// case (the rule targets unsolicited autofocus that disorients
|
|
86
|
+
// screen readers).
|
|
87
|
+
// eslint-disable-next-line
|
|
88
|
+
autoFocus
|
|
89
|
+
aria-label={resolved.placeholder}
|
|
90
|
+
sx={styles.input}
|
|
91
|
+
InputProps={{
|
|
92
|
+
startAdornment: (
|
|
93
|
+
<InputAdornment position='start'>
|
|
94
|
+
<SearchIcon fontSize='small' />
|
|
95
|
+
</InputAdornment>
|
|
96
|
+
),
|
|
97
|
+
endAdornment: local ? (
|
|
98
|
+
<InputAdornment position='end'>
|
|
99
|
+
<IconButton
|
|
100
|
+
size='small'
|
|
101
|
+
edge='end'
|
|
102
|
+
aria-label={resolved.clearAriaLabel}
|
|
103
|
+
onClick={handleClear}
|
|
104
|
+
>
|
|
105
|
+
<ClearIcon fontSize='small' />
|
|
106
|
+
</IconButton>
|
|
107
|
+
</InputAdornment>
|
|
108
|
+
) : null,
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SxProps, Theme } from '@mui/material'
|
|
2
|
+
|
|
3
|
+
export const styles = {
|
|
4
|
+
toggle: {
|
|
5
|
+
p: 0.5,
|
|
6
|
+
'& .MuiSvgIcon-root': { fontSize: 20 },
|
|
7
|
+
},
|
|
8
|
+
toggleActive: {
|
|
9
|
+
background: (theme: Theme) => theme.palette.primary.relatedLight,
|
|
10
|
+
},
|
|
11
|
+
input: {
|
|
12
|
+
width: '100%',
|
|
13
|
+
mb: 1,
|
|
14
|
+
},
|
|
15
|
+
} satisfies Record<string, SxProps<Theme>>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react'
|
|
3
|
+
import { Provider } from '../../provider/widget-provider'
|
|
4
|
+
import { clearAllWidgetStores, getWidgetStore } from '../../stores'
|
|
5
|
+
import { StackToggle } from './stack-toggle'
|
|
6
|
+
|
|
7
|
+
beforeEach(() => clearAllWidgetStores())
|
|
8
|
+
afterEach(() => clearAllWidgetStores())
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Stack/Zoom/Brush share the same toggle wiring. This file is the exemplar.
|
|
12
|
+
* The transforms themselves are tested in `transforms.test.ts` /
|
|
13
|
+
* `…/zoom-toggle/transforms.test.ts` / `…/brush-toggle/transforms.test.ts`.
|
|
14
|
+
*/
|
|
15
|
+
describe('<StackToggle>', () => {
|
|
16
|
+
it('starts disabled by default and uses the off-state label', () => {
|
|
17
|
+
render(
|
|
18
|
+
<Provider id='st1' data={[]}>
|
|
19
|
+
<StackToggle />
|
|
20
|
+
</Provider>,
|
|
21
|
+
)
|
|
22
|
+
const btn = screen.getByRole('button', { name: 'Stack series' })
|
|
23
|
+
expect(btn.getAttribute('aria-pressed')).toBe('false')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('toggles aria-pressed and label on click', () => {
|
|
27
|
+
render(
|
|
28
|
+
<Provider id='st2' data={[]}>
|
|
29
|
+
<StackToggle />
|
|
30
|
+
</Provider>,
|
|
31
|
+
)
|
|
32
|
+
fireEvent.click(screen.getByRole('button', { name: 'Stack series' }))
|
|
33
|
+
const after = screen.getByRole('button', { name: 'Unstack series' })
|
|
34
|
+
expect(after.getAttribute('aria-pressed')).toBe('true')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('persists the enabled flag on the widget store under transformStates', () => {
|
|
38
|
+
render(
|
|
39
|
+
<Provider id='st3' data={[]}>
|
|
40
|
+
<StackToggle />
|
|
41
|
+
</Provider>,
|
|
42
|
+
)
|
|
43
|
+
fireEvent.click(screen.getByRole('button', { name: 'Stack series' }))
|
|
44
|
+
expect(
|
|
45
|
+
getWidgetStore('st3').getState().transformStates['stack-toggle']?.enabled,
|
|
46
|
+
).toBe(true)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('initialEnabled=true mounts already-on', () => {
|
|
50
|
+
render(
|
|
51
|
+
<Provider id='st4' data={[]}>
|
|
52
|
+
<StackToggle initialEnabled />
|
|
53
|
+
</Provider>,
|
|
54
|
+
)
|
|
55
|
+
expect(
|
|
56
|
+
screen
|
|
57
|
+
.getByRole('button', { name: 'Unstack series' })
|
|
58
|
+
.getAttribute('aria-pressed'),
|
|
59
|
+
).toBe('true')
|
|
60
|
+
})
|
|
61
|
+
})
|