@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,389 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from 'react'
|
|
2
|
+
import { Box, useTheme } from '@mui/material'
|
|
3
|
+
import { CategoryRowSingle } from './components/category-row-single'
|
|
4
|
+
import { CategoryRowMulti } from './components/category-row-multi'
|
|
5
|
+
import { CategoryRowStacked } from './components/category-row-stacked'
|
|
6
|
+
import { CategoryRowOther } from './components/category-row-other'
|
|
7
|
+
import { CategoryLegend } from './components/category-legend'
|
|
8
|
+
import type {
|
|
9
|
+
CategoryKey,
|
|
10
|
+
CategoryLabels,
|
|
11
|
+
CategorySeriesConfig,
|
|
12
|
+
CategorySize,
|
|
13
|
+
CategoryWidgetData,
|
|
14
|
+
} from './types'
|
|
15
|
+
import { styles } from './style'
|
|
16
|
+
|
|
17
|
+
const DEFAULT_MAX_ITEMS = 20
|
|
18
|
+
|
|
19
|
+
// Fallback viewport height used in scroll mode ONLY when no natural
|
|
20
|
+
// measurement is available yet — i.e., the consumer mounts directly into
|
|
21
|
+
// `maxItems === 0` (e.g., SearcherToggle pre-enabled), so the list has
|
|
22
|
+
// never rendered in capped form for us to measure.
|
|
23
|
+
//
|
|
24
|
+
// small: label(~20) + gap(4) + bar(4) + list-gap(8) ≈ 36
|
|
25
|
+
// medium: label(~20) + gap(4) + bar(12) + list-gap(8) ≈ 44
|
|
26
|
+
const ROW_HEIGHT_PX: Record<CategorySize, number> = { small: 36, medium: 44 }
|
|
27
|
+
const SCROLL_VIEWPORT_FALLBACK_ROWS = 8
|
|
28
|
+
|
|
29
|
+
export interface CategoryUIProps {
|
|
30
|
+
data: CategoryWidgetData
|
|
31
|
+
/** Currently-selected category names (destination-owned). */
|
|
32
|
+
selection?: readonly CategoryKey[]
|
|
33
|
+
/** Fires with the next selection set when a row is clicked. */
|
|
34
|
+
onSelectionChange?: (next: readonly CategoryKey[]) => void
|
|
35
|
+
/** Number formatter applied to each row's value. */
|
|
36
|
+
formatter?: (value: number) => string
|
|
37
|
+
/**
|
|
38
|
+
* Display-only transform for category names. Selection callbacks always
|
|
39
|
+
* receive the raw `item.name` regardless of this formatter.
|
|
40
|
+
*/
|
|
41
|
+
labelFormatter?: (value: string | number) => string | number
|
|
42
|
+
/**
|
|
43
|
+
* Per-series metadata. Enables the legend (for multi-series) and
|
|
44
|
+
* overrides palette colors per series index. Length need not match
|
|
45
|
+
* `data.length`; mismatches degrade gracefully (extras ignored, gaps
|
|
46
|
+
* fall back to palette).
|
|
47
|
+
*/
|
|
48
|
+
series?: readonly CategorySeriesConfig[]
|
|
49
|
+
/**
|
|
50
|
+
* Caps the number of visible category rows.
|
|
51
|
+
*
|
|
52
|
+
* - `undefined` (omitted) — caps at {@link DEFAULT_MAX_ITEMS} (20).
|
|
53
|
+
* Surplus rows fold into a single italic "Other (X more)" footer.
|
|
54
|
+
* `undefined` cannot mean "no cap" because it's consumed by the
|
|
55
|
+
* default-parameter syntax — pass `null` instead.
|
|
56
|
+
* - positive finite N — same as the default but with a custom cap.
|
|
57
|
+
* - `0` — **no cap WITH scroll**: every row renders inside a
|
|
58
|
+
* fixed-height viewport that scrolls internally. The viewport's
|
|
59
|
+
* max-height is the list's natural `clientHeight` measured on the
|
|
60
|
+
* first render where the list was NOT in scroll mode (i.e., the
|
|
61
|
+
* capped view) — frozen for the component's lifetime. If the
|
|
62
|
+
* consumer mounts directly into scroll mode and we never see a
|
|
63
|
+
* capped render, the viewport falls back to `8 × ROW_HEIGHT_PX`.
|
|
64
|
+
* Composers flip into this mode while the user is searching
|
|
65
|
+
* (`maxItems = searcherOpen ? 0 : userMaxItems`) so the widget
|
|
66
|
+
* card height stays stable.
|
|
67
|
+
* - `null` / `Infinity` / negative — **no cap, no scroll**: render
|
|
68
|
+
* every row; the list grows with content. Matches v1's "undefined"
|
|
69
|
+
* behavior. Use `null` as the canonical explicit form.
|
|
70
|
+
*/
|
|
71
|
+
maxItems?: number | null
|
|
72
|
+
/** Labels for the "Other" overflow row. `{count}` placeholder is replaced. */
|
|
73
|
+
labels?: CategoryLabels
|
|
74
|
+
/** Manual override for the bar-width denominator. */
|
|
75
|
+
maxOverride?: number
|
|
76
|
+
/**
|
|
77
|
+
* Visual density of the bar primitive. `'small'` (default) keeps the
|
|
78
|
+
* historical 4px-tall pill; `'medium'` switches to a 12px-tall track
|
|
79
|
+
* with a 2px corner radius. Only the bar track + fill change.
|
|
80
|
+
*/
|
|
81
|
+
size?: CategorySize
|
|
82
|
+
/**
|
|
83
|
+
* Multi-series stacked mode. When `true` and `data.length > 1`, each
|
|
84
|
+
* category renders as a single segmented bar (one segment per series)
|
|
85
|
+
* with a `formatter(sum)` total in the header and a per-series
|
|
86
|
+
* breakdown line below. Composers typically thread this from
|
|
87
|
+
* `useTransformEnabled(id, 'stack-toggle')`.
|
|
88
|
+
*
|
|
89
|
+
* No-op for single-series data — same convention as the legend.
|
|
90
|
+
*/
|
|
91
|
+
stacked?: boolean
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface GroupedRow {
|
|
95
|
+
name: CategoryKey
|
|
96
|
+
values: number[]
|
|
97
|
+
/** Per-series per-row color override (first non-undefined wins). */
|
|
98
|
+
rowColors: (string | undefined)[]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Group items by `name` across series so each unique name produces one
|
|
103
|
+
* row containing N values (zero-filled where a series has no entry for
|
|
104
|
+
* that name). First-seen order across series is preserved.
|
|
105
|
+
*
|
|
106
|
+
* Ported from v1
|
|
107
|
+
* (`packages/react-ui/src/widgets/category/category-ui.tsx:137-166`)
|
|
108
|
+
* with readonly typing + per-row color capture.
|
|
109
|
+
*/
|
|
110
|
+
function generateGroupedData(data: CategoryWidgetData): GroupedRow[] {
|
|
111
|
+
if (!data || data.length === 0) return []
|
|
112
|
+
const seriesCount = Math.max(data.length, 1)
|
|
113
|
+
const grouped = new Map<CategoryKey, GroupedRow>()
|
|
114
|
+
const order: CategoryKey[] = []
|
|
115
|
+
for (let s = 0; s < data.length; s++) {
|
|
116
|
+
const series = data[s] ?? []
|
|
117
|
+
for (const item of series) {
|
|
118
|
+
let row = grouped.get(item.name)
|
|
119
|
+
if (!row) {
|
|
120
|
+
row = {
|
|
121
|
+
name: item.name,
|
|
122
|
+
values: new Array<number>(seriesCount).fill(0),
|
|
123
|
+
rowColors: new Array<string | undefined>(seriesCount).fill(undefined),
|
|
124
|
+
}
|
|
125
|
+
grouped.set(item.name, row)
|
|
126
|
+
order.push(item.name)
|
|
127
|
+
}
|
|
128
|
+
row.values[s] = item.value
|
|
129
|
+
row.rowColors[s] = item.color
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return order.map((k) => grouped.get(k)!)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Pure presentational component for the Category widget. Renders
|
|
137
|
+
* single-series rows (`data.length === 1`) as a compact grid or
|
|
138
|
+
* multi-series rows (`data.length > 1`) as stacked-bar groups, capped at
|
|
139
|
+
* `maxItems` with an overflow summary, and an optional sticky color
|
|
140
|
+
* legend when `series` metadata is supplied.
|
|
141
|
+
*
|
|
142
|
+
* Selection is destination-owned: clicking a row fires
|
|
143
|
+
* `onSelectionChange(next)` with the toggled set; the consumer keeps the
|
|
144
|
+
* list in their own store. `aria-pressed` + Enter/Space keyboard
|
|
145
|
+
* activation give full a11y parity with the mouse path.
|
|
146
|
+
*
|
|
147
|
+
* Returns `null` when there's nothing to render — `Widget.State` is the
|
|
148
|
+
* empty-state authority in the canonical compositor.
|
|
149
|
+
*/
|
|
150
|
+
export function CategoryUI({
|
|
151
|
+
data,
|
|
152
|
+
selection,
|
|
153
|
+
onSelectionChange,
|
|
154
|
+
formatter,
|
|
155
|
+
labelFormatter,
|
|
156
|
+
series,
|
|
157
|
+
maxItems = DEFAULT_MAX_ITEMS,
|
|
158
|
+
labels,
|
|
159
|
+
maxOverride,
|
|
160
|
+
size = 'small',
|
|
161
|
+
stacked = false,
|
|
162
|
+
}: CategoryUIProps) {
|
|
163
|
+
const theme = useTheme()
|
|
164
|
+
const fmt = formatter ?? ((n: number) => String(n))
|
|
165
|
+
|
|
166
|
+
const hasSelection = !!selection && selection.length > 0
|
|
167
|
+
const selectionSet = useMemo(
|
|
168
|
+
() => new Set<CategoryKey>(selection ?? []),
|
|
169
|
+
[selection],
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
const toggle = useCallback(
|
|
173
|
+
(name: CategoryKey) => {
|
|
174
|
+
if (!onSelectionChange) return
|
|
175
|
+
const cur = selection ?? []
|
|
176
|
+
const next = cur.includes(name)
|
|
177
|
+
? cur.filter((n) => n !== name)
|
|
178
|
+
: [...cur, name]
|
|
179
|
+
onSelectionChange(next)
|
|
180
|
+
},
|
|
181
|
+
[onSelectionChange, selection],
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
// Palette: same convention as Bar/Pie/Histogram/Scatterplot/Timeseries v2.
|
|
185
|
+
const paletteColors = useMemo<readonly string[]>(
|
|
186
|
+
() => [
|
|
187
|
+
theme.palette.secondary.main,
|
|
188
|
+
...Object.values(
|
|
189
|
+
(theme.palette as { qualitative?: { bold?: Record<string, string> } })
|
|
190
|
+
.qualitative?.bold ?? {},
|
|
191
|
+
),
|
|
192
|
+
],
|
|
193
|
+
[theme],
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
const colorAt = useCallback(
|
|
197
|
+
(seriesIndex: number, rowColor?: string): string => {
|
|
198
|
+
if (rowColor) return rowColor
|
|
199
|
+
const seriesColor = series?.[seriesIndex]?.color
|
|
200
|
+
if (seriesColor) return seriesColor
|
|
201
|
+
return (
|
|
202
|
+
paletteColors[seriesIndex % paletteColors.length] ??
|
|
203
|
+
theme.palette.secondary.main
|
|
204
|
+
)
|
|
205
|
+
},
|
|
206
|
+
[series, paletteColors, theme],
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
// Dim color for non-selected rows when a selection exists. Swapped in
|
|
210
|
+
// at the bar-fill level only — text + track stay at their real colors.
|
|
211
|
+
// Theme-driven so it survives palette swaps.
|
|
212
|
+
const dimColor = theme.palette.action.disabled
|
|
213
|
+
|
|
214
|
+
const grouped = useMemo(() => generateGroupedData(data), [data])
|
|
215
|
+
|
|
216
|
+
const maxValue = useMemo(() => {
|
|
217
|
+
if (typeof maxOverride === 'number' && maxOverride > 0) return maxOverride
|
|
218
|
+
let m = 0
|
|
219
|
+
for (const row of grouped) {
|
|
220
|
+
for (const v of row.values) if (v > m) m = v
|
|
221
|
+
}
|
|
222
|
+
return m
|
|
223
|
+
}, [grouped, maxOverride])
|
|
224
|
+
|
|
225
|
+
// Three modes:
|
|
226
|
+
// * positive finite N (default `DEFAULT_MAX_ITEMS = 20` when prop
|
|
227
|
+
// omitted): cap at N rows; surplus folds into "Other (X more)".
|
|
228
|
+
// * `0`: no cap WITH scroll — every row renders, the list locks to a
|
|
229
|
+
// fixed viewport and scrolls internally. Composers use this to
|
|
230
|
+
// bypass pagination while the user is searching:
|
|
231
|
+
// `maxItems = searcherOpen ? 0 : userMaxItems`
|
|
232
|
+
// * `null` / `Infinity` / negative: no cap, no scroll — every row
|
|
233
|
+
// renders and the list grows with content. `null` is the canonical
|
|
234
|
+
// explicit form (`undefined` is consumed by the default param above).
|
|
235
|
+
const scrollMode = maxItems === 0
|
|
236
|
+
|
|
237
|
+
// Natural-height measurement. In scroll mode (`maxItems === 0`,
|
|
238
|
+
// set by the composer when the SearcherToggle is open) every row
|
|
239
|
+
// renders inside a scrollable viewport. The viewport's max-height
|
|
240
|
+
// must match the pre-overflow content area — i.e., whatever the
|
|
241
|
+
// list was rendering BEFORE the composer dropped the cap.
|
|
242
|
+
//
|
|
243
|
+
// We measure the list's `clientHeight` exactly once, the first time
|
|
244
|
+
// it attaches while NOT in scroll mode (otherwise we'd capture the
|
|
245
|
+
// wrong layout). Once set, `naturalHeight` is the lock anchor
|
|
246
|
+
// forever — matches v1's frozen-at-mount semantics, just with a
|
|
247
|
+
// real DOM measurement instead of a hard-coded constant.
|
|
248
|
+
//
|
|
249
|
+
// Implemented via a callback ref instead of `useLayoutEffect` so
|
|
250
|
+
// setState fires during commit, not inside an effect — satisfies
|
|
251
|
+
// the `react-hooks/set-state-in-effect` rule. React invokes
|
|
252
|
+
// callback refs on attach (and re-invokes them when the callback
|
|
253
|
+
// identity changes, which it does when `scrollMode` flips), so
|
|
254
|
+
// toggling the searcher off after a scroll-mode mount triggers the
|
|
255
|
+
// first measurement at that point.
|
|
256
|
+
//
|
|
257
|
+
// Fallback: if the consumer never lands a non-scroll render
|
|
258
|
+
// (e.g., searcher pre-enabled and never closed), `naturalHeight`
|
|
259
|
+
// stays `null` → viewport falls back to `8 × ROW_HEIGHT_PX`.
|
|
260
|
+
const measuredRef = useRef(false)
|
|
261
|
+
const [naturalHeight, setNaturalHeight] = useState<number | null>(null)
|
|
262
|
+
const listRefCallback = useCallback(
|
|
263
|
+
(node: HTMLDivElement | null) => {
|
|
264
|
+
if (!node) return
|
|
265
|
+
if (measuredRef.current) return
|
|
266
|
+
if (scrollMode) return
|
|
267
|
+
const h = node.clientHeight
|
|
268
|
+
if (h > 0) {
|
|
269
|
+
measuredRef.current = true
|
|
270
|
+
setNaturalHeight(h)
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
[scrollMode],
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
if (grouped.length === 0) return null
|
|
277
|
+
|
|
278
|
+
const hasCap =
|
|
279
|
+
typeof maxItems === 'number' && Number.isFinite(maxItems) && maxItems > 0
|
|
280
|
+
const visible = hasCap ? grouped.slice(0, maxItems) : grouped
|
|
281
|
+
const hiddenCount = hasCap ? grouped.length - visible.length : 0
|
|
282
|
+
|
|
283
|
+
const isMulti = data.length > 1
|
|
284
|
+
const hasLegend = isMulti && !!series && series.length > 0
|
|
285
|
+
|
|
286
|
+
// Fallback viewport height matches the documented "8 × ROW_HEIGHT_PX"
|
|
287
|
+
// (see the constants at the top of the file). Earlier code multiplied
|
|
288
|
+
// this by `seriesCount`, making a 3-series widget render 3× the
|
|
289
|
+
// intended viewport on the first frame before `naturalHeight` was
|
|
290
|
+
// measured — a visible layout jump.
|
|
291
|
+
const scrollMaxHeight = scrollMode
|
|
292
|
+
? (naturalHeight ?? ROW_HEIGHT_PX[size] * SCROLL_VIEWPORT_FALLBACK_ROWS)
|
|
293
|
+
: undefined
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
<Box sx={styles.root}>
|
|
297
|
+
<Box
|
|
298
|
+
ref={listRefCallback}
|
|
299
|
+
sx={styles.list}
|
|
300
|
+
style={
|
|
301
|
+
scrollMaxHeight !== undefined
|
|
302
|
+
? { maxHeight: scrollMaxHeight, overflowY: 'auto' }
|
|
303
|
+
: undefined
|
|
304
|
+
}
|
|
305
|
+
>
|
|
306
|
+
{visible.map((row) => {
|
|
307
|
+
const selected = selectionSet.has(row.name)
|
|
308
|
+
const dimmed = hasSelection && !selected
|
|
309
|
+
const displayName = labelFormatter
|
|
310
|
+
? labelFormatter(row.name)
|
|
311
|
+
: undefined
|
|
312
|
+
// When the row is dimmed, every series' bar fill is replaced
|
|
313
|
+
// with `dimColor`. Text + track are untouched. This is the
|
|
314
|
+
// ONLY visual difference between selected and non-selected
|
|
315
|
+
// rows — no row-level opacity, no `rowSelected` bg tint.
|
|
316
|
+
const fill = (i: number): string =>
|
|
317
|
+
dimmed ? dimColor : colorAt(i, row.rowColors[i])
|
|
318
|
+
if (isMulti) {
|
|
319
|
+
if (stacked) {
|
|
320
|
+
// Stacked-mode branch: one segmented bar per row. Toggling
|
|
321
|
+
// `stacked` after the natural-height measurement does NOT
|
|
322
|
+
// re-trigger measurement (see the `naturalHeight` comment
|
|
323
|
+
// above) — accepted trade-off: stacked rows have a slightly
|
|
324
|
+
// different height, so the scroll viewport may show extra
|
|
325
|
+
// whitespace after the toggle. Visual only, not functional.
|
|
326
|
+
// Stacked rows are per-row normalized — they don't take
|
|
327
|
+
// the global `maxValue`. Each row's bar fills 100% of the
|
|
328
|
+
// track and the segments split it by `value_i / sum`. The
|
|
329
|
+
// numeric total in the header preserves the per-row
|
|
330
|
+
// magnitude information.
|
|
331
|
+
return (
|
|
332
|
+
<CategoryRowStacked
|
|
333
|
+
key={String(row.name)}
|
|
334
|
+
name={row.name}
|
|
335
|
+
displayName={displayName}
|
|
336
|
+
values={row.values}
|
|
337
|
+
colors={row.values.map((_, i) => fill(i))}
|
|
338
|
+
seriesNames={series?.map((s) => s.name) ?? []}
|
|
339
|
+
formatter={fmt}
|
|
340
|
+
selected={selected}
|
|
341
|
+
onToggle={toggle}
|
|
342
|
+
size={size}
|
|
343
|
+
/>
|
|
344
|
+
)
|
|
345
|
+
}
|
|
346
|
+
return (
|
|
347
|
+
<CategoryRowMulti
|
|
348
|
+
key={String(row.name)}
|
|
349
|
+
name={row.name}
|
|
350
|
+
displayName={displayName}
|
|
351
|
+
values={row.values}
|
|
352
|
+
colors={row.values.map((_, i) => fill(i))}
|
|
353
|
+
maxValue={maxValue}
|
|
354
|
+
formatter={fmt}
|
|
355
|
+
selected={selected}
|
|
356
|
+
onToggle={toggle}
|
|
357
|
+
size={size}
|
|
358
|
+
/>
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
return (
|
|
362
|
+
<CategoryRowSingle
|
|
363
|
+
key={String(row.name)}
|
|
364
|
+
name={row.name}
|
|
365
|
+
displayName={displayName}
|
|
366
|
+
value={row.values[0] ?? 0}
|
|
367
|
+
maxValue={maxValue}
|
|
368
|
+
color={fill(0)}
|
|
369
|
+
formatter={fmt}
|
|
370
|
+
selected={selected}
|
|
371
|
+
onToggle={toggle}
|
|
372
|
+
size={size}
|
|
373
|
+
/>
|
|
374
|
+
)
|
|
375
|
+
})}
|
|
376
|
+
{hiddenCount > 0 && (
|
|
377
|
+
<CategoryRowOther
|
|
378
|
+
hiddenCount={hiddenCount}
|
|
379
|
+
otherLabel={labels?.other}
|
|
380
|
+
otherCountLabel={labels?.otherCount}
|
|
381
|
+
/>
|
|
382
|
+
)}
|
|
383
|
+
</Box>
|
|
384
|
+
{hasLegend && series && (
|
|
385
|
+
<CategoryLegend series={series} colorAt={(i) => colorAt(i)} />
|
|
386
|
+
)}
|
|
387
|
+
</Box>
|
|
388
|
+
)
|
|
389
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
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 {
|
|
5
|
+
clearAllWidgetStores,
|
|
6
|
+
useTransformEnabled,
|
|
7
|
+
useWidgetId,
|
|
8
|
+
} from '../stores'
|
|
9
|
+
import { Category } from './category'
|
|
10
|
+
import { RelativeData } from '../actions/relative-data/relative-data'
|
|
11
|
+
import type { CategoryWidgetData } from './types'
|
|
12
|
+
|
|
13
|
+
beforeEach(() => clearAllWidgetStores())
|
|
14
|
+
afterEach(() => clearAllWidgetStores())
|
|
15
|
+
|
|
16
|
+
// Replicates `CategoryActionWiring` from the storybook composer
|
|
17
|
+
// (apps/storybook/stories/modules/widgets/category/category.tsx). The
|
|
18
|
+
// composer-level wiring isn't testable in `apps/storybook` (no vitest
|
|
19
|
+
// infra), so we re-implement just the relative-data branch here and
|
|
20
|
+
// assert the bar-width math end-to-end through Provider → action →
|
|
21
|
+
// bridge → UI.
|
|
22
|
+
function Wired({ maxOverride }: { maxOverride?: number }) {
|
|
23
|
+
const id = useWidgetId()
|
|
24
|
+
const relativeDataActive = useTransformEnabled(id, 'relative-data')
|
|
25
|
+
const effectiveMaxOverride = relativeDataActive ? 100 : maxOverride
|
|
26
|
+
return <Category maxOverride={effectiveMaxOverride} />
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Single-series dataset where the max value is 1000 so percent values
|
|
30
|
+
// map to round numbers we can match exactly against bar widths.
|
|
31
|
+
const DATA: CategoryWidgetData = [
|
|
32
|
+
[
|
|
33
|
+
{ name: 'A', value: 1000 },
|
|
34
|
+
{ name: 'B', value: 500 },
|
|
35
|
+
{ name: 'C', value: 250 },
|
|
36
|
+
],
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
function getBarFills(): HTMLElement[] {
|
|
40
|
+
return Array.from(
|
|
41
|
+
document.querySelectorAll<HTMLElement>('[data-bar-fill="true"]'),
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('Category + RelativeData composer wiring', () => {
|
|
46
|
+
it('default (RelativeData off) → bars scale to data max', () => {
|
|
47
|
+
render(
|
|
48
|
+
<Provider id='cat-rd-off' data={DATA}>
|
|
49
|
+
<RelativeData />
|
|
50
|
+
<Wired />
|
|
51
|
+
</Provider>,
|
|
52
|
+
)
|
|
53
|
+
const fills = getBarFills()
|
|
54
|
+
expect(fills).toHaveLength(3)
|
|
55
|
+
// 1000/1000, 500/1000, 250/1000
|
|
56
|
+
expect(fills[0]!.style.width).toBe('100%')
|
|
57
|
+
expect(fills[1]!.style.width).toBe('50%')
|
|
58
|
+
expect(fills[2]!.style.width).toBe('25%')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('clicking the % action flips bars to a 100-denominator', () => {
|
|
62
|
+
render(
|
|
63
|
+
<Provider id='cat-rd-toggle' data={DATA}>
|
|
64
|
+
<RelativeData />
|
|
65
|
+
<Wired />
|
|
66
|
+
</Provider>,
|
|
67
|
+
)
|
|
68
|
+
// Toggle ON. RelativeData rewrites data values into percentages
|
|
69
|
+
// (A=1000/1750 ≈ 57.14, B=500/1750 ≈ 28.57, C=250/1750 ≈ 14.29) AND
|
|
70
|
+
// the composer wiring forces maxOverride=100 so the bar widths
|
|
71
|
+
// match those percent values directly.
|
|
72
|
+
fireEvent.click(screen.getByRole('button', { name: /relative|percent/i }))
|
|
73
|
+
const fills = getBarFills()
|
|
74
|
+
expect(fills).toHaveLength(3)
|
|
75
|
+
// Allow a small rounding tolerance — the percent transform produces
|
|
76
|
+
// floats, the bar math multiplies by 100 again.
|
|
77
|
+
const a = parseFloat(fills[0]!.style.width)
|
|
78
|
+
const b = parseFloat(fills[1]!.style.width)
|
|
79
|
+
const c = parseFloat(fills[2]!.style.width)
|
|
80
|
+
expect(a).toBeGreaterThan(55)
|
|
81
|
+
expect(a).toBeLessThan(60)
|
|
82
|
+
expect(b).toBeGreaterThan(27)
|
|
83
|
+
expect(b).toBeLessThan(30)
|
|
84
|
+
expect(c).toBeGreaterThan(13)
|
|
85
|
+
expect(c).toBeLessThan(16)
|
|
86
|
+
// The largest bar must be NOT 100% — that's the whole point of the
|
|
87
|
+
// fix. Without the wiring, A would have been 100% (largest of the
|
|
88
|
+
// percent series).
|
|
89
|
+
expect(a).toBeLessThan(100)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('toggling off again restores data-max scaling', () => {
|
|
93
|
+
render(
|
|
94
|
+
<Provider id='cat-rd-restore' data={DATA}>
|
|
95
|
+
<RelativeData />
|
|
96
|
+
<Wired />
|
|
97
|
+
</Provider>,
|
|
98
|
+
)
|
|
99
|
+
const button = screen.getByRole('button', { name: /relative|percent/i })
|
|
100
|
+
fireEvent.click(button) // on
|
|
101
|
+
fireEvent.click(button) // off
|
|
102
|
+
const fills = getBarFills()
|
|
103
|
+
expect(fills[0]!.style.width).toBe('100%')
|
|
104
|
+
expect(fills[1]!.style.width).toBe('50%')
|
|
105
|
+
expect(fills[2]!.style.width).toBe('25%')
|
|
106
|
+
})
|
|
107
|
+
})
|
|
@@ -0,0 +1,85 @@
|
|
|
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 {
|
|
5
|
+
clearAllWidgetStores,
|
|
6
|
+
useTransformEnabled,
|
|
7
|
+
useWidgetId,
|
|
8
|
+
} from '../stores'
|
|
9
|
+
import { Category } from './category'
|
|
10
|
+
import { StackToggle } from '../actions/stack-toggle/stack-toggle'
|
|
11
|
+
import type { CategoryWidgetData } from './types'
|
|
12
|
+
|
|
13
|
+
beforeEach(() => clearAllWidgetStores())
|
|
14
|
+
afterEach(() => clearAllWidgetStores())
|
|
15
|
+
|
|
16
|
+
// Replicates the stack-toggle branch of `CategoryActionWiring` from the
|
|
17
|
+
// storybook composer. The composer-level wiring isn't testable in
|
|
18
|
+
// `apps/storybook` (no vitest infra), so we re-implement just the
|
|
19
|
+
// stack-toggle branch here and assert the action → bridge → UI path
|
|
20
|
+
// end-to-end through Provider → action → bridge → UI.
|
|
21
|
+
function Wired() {
|
|
22
|
+
const id = useWidgetId()
|
|
23
|
+
const stacked = useTransformEnabled(id, 'stack-toggle')
|
|
24
|
+
return (
|
|
25
|
+
<Category series={[{ name: 'Women' }, { name: 'Men' }]} stacked={stacked} />
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const DATA: CategoryWidgetData = [
|
|
30
|
+
[
|
|
31
|
+
{ name: 'A', value: 45 },
|
|
32
|
+
{ name: 'B', value: 30 },
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
{ name: 'A', value: 32 },
|
|
36
|
+
{ name: 'B', value: 18 },
|
|
37
|
+
],
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
describe('Category + StackToggle composer wiring', () => {
|
|
41
|
+
it('default (StackToggle off) → multi-series renders one bar per series per row', () => {
|
|
42
|
+
const { container } = render(
|
|
43
|
+
<Provider id='cat-stack-off' data={DATA}>
|
|
44
|
+
<StackToggle />
|
|
45
|
+
<Wired />
|
|
46
|
+
</Provider>,
|
|
47
|
+
)
|
|
48
|
+
// CategoryRowMulti renders one track per series per row → 2 rows × 2 = 4.
|
|
49
|
+
expect(container.querySelectorAll('[data-size]').length).toBe(4)
|
|
50
|
+
// No breakdown text from the stacked row.
|
|
51
|
+
expect(screen.queryByText(/Women: 45/)).toBeNull()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('clicking the stack action flips multi-series rendering to stacked rows', () => {
|
|
55
|
+
const { container } = render(
|
|
56
|
+
<Provider id='cat-stack-on' data={DATA}>
|
|
57
|
+
<StackToggle />
|
|
58
|
+
<Wired />
|
|
59
|
+
</Provider>,
|
|
60
|
+
)
|
|
61
|
+
fireEvent.click(screen.getByRole('button', { name: /stack|unstack/i }))
|
|
62
|
+
// Stacked rendering: one track per row → 2 tracks total.
|
|
63
|
+
expect(container.querySelectorAll('[data-size]').length).toBe(2)
|
|
64
|
+
// Breakdown text appears.
|
|
65
|
+
expect(screen.getByText('Women: 45')).toBeTruthy()
|
|
66
|
+
expect(screen.getByText('Men: 32')).toBeTruthy()
|
|
67
|
+
// Totals show in the header.
|
|
68
|
+
expect(screen.getByText('77')).toBeTruthy() // A: 45 + 32
|
|
69
|
+
expect(screen.getByText('48')).toBeTruthy() // B: 30 + 18
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('toggling off again restores CategoryRowMulti rendering', () => {
|
|
73
|
+
const { container } = render(
|
|
74
|
+
<Provider id='cat-stack-restore' data={DATA}>
|
|
75
|
+
<StackToggle />
|
|
76
|
+
<Wired />
|
|
77
|
+
</Provider>,
|
|
78
|
+
)
|
|
79
|
+
const button = screen.getByRole('button', { name: /stack|unstack/i })
|
|
80
|
+
fireEvent.click(button) // on
|
|
81
|
+
fireEvent.click(button) // off
|
|
82
|
+
expect(container.querySelectorAll('[data-size]').length).toBe(4)
|
|
83
|
+
expect(screen.queryByText(/Women: 45/)).toBeNull()
|
|
84
|
+
})
|
|
85
|
+
})
|