@carto/ps-react-ui 4.7.1 → 4.9.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/{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-l4fNHLEg.js +213 -0
- package/dist/range-l4fNHLEg.js.map +1 -0
- package/dist/resolve-theme-color-BdojIw0K.js +47 -0
- package/dist/resolve-theme-color-BdojIw0K.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-CQCAnDLb.js +388 -0
- package/dist/table-CQCAnDLb.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 +46 -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 +53 -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 +43 -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 +51 -0
- package/dist/types/widgets-v2/index.d.ts +108 -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 +57 -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 +27 -0
- package/dist/types/widgets-v2/range/range.d.ts +24 -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 +54 -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 +40 -0
- package/dist/types/widgets-v2/table/table-ui.d.ts +44 -0
- package/dist/types/widgets-v2/table/table.d.ts +50 -0
- package/dist/types/widgets-v2/table/types.d.ts +48 -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 +60 -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/types.d.ts +25 -0
- package/dist/types/widgets-v2/utils/data-zoom-layout.d.ts +11 -0
- package/dist/types/widgets-v2/utils/index.d.ts +3 -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/utils/resolve-theme-color.d.ts +18 -0
- package/dist/types/widgets-v2/utils/resolve-theme-color.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 +330 -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 +353 -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 +387 -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 +411 -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 +358 -0
- package/dist/widgets-v2/timeseries.js.map +1 -0
- package/dist/widgets-v2/utils.js +8 -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 +71 -3
- 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 +334 -0
- package/src/widgets-v2/bar/options.ts +332 -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 +51 -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 +59 -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 +48 -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 +318 -0
- package/src/widgets-v2/histogram/options.ts +338 -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 +55 -0
- package/src/widgets-v2/index.ts +204 -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 +601 -0
- package/src/widgets-v2/pie/options.ts +513 -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 +62 -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 +136 -0
- package/src/widgets-v2/range/range-ui.tsx +278 -0
- package/src/widgets-v2/range/range.test.tsx +68 -0
- package/src/widgets-v2/range/range.tsx +52 -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 +411 -0
- package/src/widgets-v2/scatterplot/options.ts +425 -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 +59 -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 +43 -0
- package/src/widgets-v2/table/table-ui.test.tsx +200 -0
- package/src/widgets-v2/table/table-ui.tsx +364 -0
- package/src/widgets-v2/table/table.test.tsx +119 -0
- package/src/widgets-v2/table/table.tsx +179 -0
- package/src/widgets-v2/table/types.ts +55 -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 +394 -0
- package/src/widgets-v2/timeseries/options.ts +348 -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 +65 -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/types.ts +25 -0
- package/src/widgets-v2/utils/data-zoom-layout.ts +26 -0
- package/src/widgets-v2/utils/index.ts +3 -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/utils/resolve-theme-color.test.ts +43 -0
- package/src/widgets-v2/utils/resolve-theme-color.ts +34 -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,130 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, type ComponentType } from 'react'
|
|
2
|
+
import { IconButton, type SvgIconProps } from '@mui/material'
|
|
3
|
+
import LockIcon from '@mui/icons-material/Lock'
|
|
4
|
+
import LockOpenIcon from '@mui/icons-material/LockOpen'
|
|
5
|
+
import { Tooltip } from '../../../components'
|
|
6
|
+
import { useTransform, useWidgetId } from '../../stores'
|
|
7
|
+
import type { TransformPair } from '../../stores'
|
|
8
|
+
import { filterByLockedItems } from './transforms'
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_LOCK_SELECTION_LABELS,
|
|
11
|
+
type LockSelectionLabels,
|
|
12
|
+
} from './labels'
|
|
13
|
+
import { styles } from './style'
|
|
14
|
+
|
|
15
|
+
const LOCK_SELECTION_DESCRIPTOR = {
|
|
16
|
+
id: 'lock-selection',
|
|
17
|
+
type: 'data' as const,
|
|
18
|
+
order: 30,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type LockSelectionKey = string | number
|
|
22
|
+
|
|
23
|
+
export interface LockSelectionProps {
|
|
24
|
+
/**
|
|
25
|
+
* Currently-selected items (destination-owned). On lock, this set is
|
|
26
|
+
* snapshotted into `lockedItems` via `onLockChange`.
|
|
27
|
+
*/
|
|
28
|
+
selection: readonly LockSelectionKey[]
|
|
29
|
+
/**
|
|
30
|
+
* Currently-locked items (destination-owned). When non-empty, the widget's
|
|
31
|
+
* data is filtered to these items via the registered transform.
|
|
32
|
+
*/
|
|
33
|
+
lockedItems: readonly LockSelectionKey[]
|
|
34
|
+
/**
|
|
35
|
+
* Fires when the user toggles the lock. The destination is responsible for
|
|
36
|
+
* persisting the new locked set (and re-feeding it via `lockedItems`).
|
|
37
|
+
*/
|
|
38
|
+
onLockChange: (next: readonly LockSelectionKey[]) => void
|
|
39
|
+
labels?: Partial<LockSelectionLabels>
|
|
40
|
+
/** Lock icon (default: `LockIcon`). */
|
|
41
|
+
lockIcon?: ComponentType<SvgIconProps>
|
|
42
|
+
/** Unlock icon (default: `LockOpenIcon`). */
|
|
43
|
+
unlockIcon?: ComponentType<SvgIconProps>
|
|
44
|
+
iconProps?: SvgIconProps
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Action that pins the current selection so the widget's data filters down
|
|
49
|
+
* to those items even as the user changes selections. Selection and lock
|
|
50
|
+
* state are destination-owned; this component is a controlled UI + a data
|
|
51
|
+
* transform registered against the widget's pipeline.
|
|
52
|
+
*
|
|
53
|
+
* The trigger is disabled when there is nothing to lock and nothing locked.
|
|
54
|
+
*/
|
|
55
|
+
export function LockSelection({
|
|
56
|
+
selection,
|
|
57
|
+
lockedItems,
|
|
58
|
+
onLockChange,
|
|
59
|
+
labels,
|
|
60
|
+
lockIcon: LockSvg = LockIcon,
|
|
61
|
+
unlockIcon: UnlockSvg = LockOpenIcon,
|
|
62
|
+
iconProps,
|
|
63
|
+
}: LockSelectionProps) {
|
|
64
|
+
const id = useWidgetId()
|
|
65
|
+
const _labels = { ...DEFAULT_LOCK_SELECTION_LABELS, ...labels }
|
|
66
|
+
const isLocked = lockedItems.length > 0
|
|
67
|
+
const canToggle = isLocked || selection.length > 0
|
|
68
|
+
|
|
69
|
+
// Pair memoized on lockedItems identity — useTransform re-registers the fn
|
|
70
|
+
// (which closes over the current locked set) whenever the destination feeds
|
|
71
|
+
// a new array. setEnabled drives the middleware-level `enabled` flag.
|
|
72
|
+
const pairs = useMemoPair(lockedItems)
|
|
73
|
+
const { enabled, setEnabled } = useTransform(id, pairs, {
|
|
74
|
+
initialEnabled: isLocked,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Keep middleware `enabled` in sync with destination-owned `isLocked`. The
|
|
78
|
+
// pipeline only short-circuits the transform when enabled === false, so
|
|
79
|
+
// toggling here is what makes lock/unlock actually take effect.
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (enabled !== isLocked) setEnabled(isLocked)
|
|
82
|
+
}, [enabled, isLocked, setEnabled])
|
|
83
|
+
|
|
84
|
+
const handleToggle = useCallback(() => {
|
|
85
|
+
if (isLocked) {
|
|
86
|
+
onLockChange([])
|
|
87
|
+
} else {
|
|
88
|
+
onLockChange([...selection])
|
|
89
|
+
}
|
|
90
|
+
}, [isLocked, onLockChange, selection])
|
|
91
|
+
|
|
92
|
+
const tooltip = !canToggle
|
|
93
|
+
? _labels.disabled
|
|
94
|
+
: isLocked
|
|
95
|
+
? _labels.unlock
|
|
96
|
+
: _labels.lock
|
|
97
|
+
const Icon = isLocked ? UnlockSvg : LockSvg
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<Tooltip title={tooltip}>
|
|
101
|
+
<span>
|
|
102
|
+
<IconButton
|
|
103
|
+
size='small'
|
|
104
|
+
aria-label={tooltip}
|
|
105
|
+
aria-pressed={isLocked}
|
|
106
|
+
disabled={!canToggle}
|
|
107
|
+
onClick={handleToggle}
|
|
108
|
+
sx={{ ...styles.toggle, ...(isLocked && styles.toggleActive) }}
|
|
109
|
+
>
|
|
110
|
+
<Icon fontSize='small' {...iconProps} />
|
|
111
|
+
</IconButton>
|
|
112
|
+
</span>
|
|
113
|
+
</Tooltip>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Builds a stable `[{ descriptor, fn }]` pair where `fn` closes over the
|
|
119
|
+
* latest `lockedItems`. Re-memoized whenever the array identity changes so
|
|
120
|
+
* `useTransform` re-registers the closure with the freshest data.
|
|
121
|
+
*/
|
|
122
|
+
function useMemoPair(
|
|
123
|
+
lockedItems: readonly LockSelectionKey[],
|
|
124
|
+
): readonly TransformPair[] {
|
|
125
|
+
const fn = useCallback(
|
|
126
|
+
(data: unknown) => filterByLockedItems(data, lockedItems),
|
|
127
|
+
[lockedItems],
|
|
128
|
+
)
|
|
129
|
+
return useMemo(() => [{ descriptor: LOCK_SELECTION_DESCRIPTOR, fn }], [fn])
|
|
130
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
} satisfies Record<string, SxProps<Theme>>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filters a 2D series of `{name, ...}` records, keeping only items whose
|
|
3
|
+
* `name` is in the locked set. Multi-series shape is preserved (one inner
|
|
4
|
+
* array per series). Used by the LockSelection action's data transform.
|
|
5
|
+
*/
|
|
6
|
+
export function filterByLockedItems(
|
|
7
|
+
input: unknown,
|
|
8
|
+
lockedItems: readonly (string | number)[],
|
|
9
|
+
): unknown {
|
|
10
|
+
if (lockedItems.length === 0) return input
|
|
11
|
+
if (!Array.isArray(input)) return input
|
|
12
|
+
const set = new Set<string | number>(lockedItems)
|
|
13
|
+
return input.map((series: unknown): unknown => {
|
|
14
|
+
if (!Array.isArray(series)) return series
|
|
15
|
+
return series.filter((item: unknown) => {
|
|
16
|
+
if (item == null) return false
|
|
17
|
+
if (typeof item === 'object' && 'name' in item) {
|
|
18
|
+
const name = (item as { name: unknown }).name
|
|
19
|
+
if (typeof name === 'string' || typeof name === 'number') {
|
|
20
|
+
return set.has(name)
|
|
21
|
+
}
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
return false
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { render } from '@testing-library/react'
|
|
3
|
+
import { Provider } from '../../provider/widget-provider'
|
|
4
|
+
import { clearAllWidgetStores, getWidgetStore } from '../../stores'
|
|
5
|
+
import { RelativeData } from './relative-data'
|
|
6
|
+
|
|
7
|
+
beforeEach(() => clearAllWidgetStores())
|
|
8
|
+
afterEach(() => clearAllWidgetStores())
|
|
9
|
+
|
|
10
|
+
const fmtA = (n: number) => `A${n}`
|
|
11
|
+
const fmtB = (n: number) => `B${n}`
|
|
12
|
+
|
|
13
|
+
describe('<RelativeData> — rawFormatter-driven restoration', () => {
|
|
14
|
+
it('Provider mirrors the formatter prop into both rawFormatter and formatter', () => {
|
|
15
|
+
render(
|
|
16
|
+
<Provider id='rd1' data={[]} formatter={fmtA}>
|
|
17
|
+
<RelativeData initialEnabled={false} />
|
|
18
|
+
</Provider>,
|
|
19
|
+
)
|
|
20
|
+
const s = getWidgetStore('rd1').getState()
|
|
21
|
+
expect(s.rawFormatter).toBe(fmtA)
|
|
22
|
+
expect(s.formatter).toBe(fmtA)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('initialEnabled=true installs the percent formatter and leaves rawFormatter untouched', () => {
|
|
26
|
+
render(
|
|
27
|
+
<Provider id='rd2' data={[]} formatter={fmtA}>
|
|
28
|
+
<RelativeData initialEnabled={true} />
|
|
29
|
+
</Provider>,
|
|
30
|
+
)
|
|
31
|
+
const s = getWidgetStore('rd2').getState()
|
|
32
|
+
expect(s.rawFormatter).toBe(fmtA)
|
|
33
|
+
expect(typeof s.formatter).toBe('function')
|
|
34
|
+
expect(s.formatter).not.toBe(fmtA)
|
|
35
|
+
// Sanity: the override is the percent formatter (50 → "50%" via Intl).
|
|
36
|
+
expect(s.formatter?.(50)).toMatch(/%$/)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('consumer prop change while enabled updates rawFormatter; effect re-applies percent', () => {
|
|
40
|
+
const { rerender } = render(
|
|
41
|
+
<Provider id='rd3' data={[]} formatter={fmtA}>
|
|
42
|
+
<RelativeData initialEnabled={true} />
|
|
43
|
+
</Provider>,
|
|
44
|
+
)
|
|
45
|
+
const store = getWidgetStore('rd3')
|
|
46
|
+
expect(store.getState().rawFormatter).toBe(fmtA)
|
|
47
|
+
const beforePercent = store.getState().formatter
|
|
48
|
+
|
|
49
|
+
rerender(
|
|
50
|
+
<Provider id='rd3' data={[]} formatter={fmtB}>
|
|
51
|
+
<RelativeData initialEnabled={true} />
|
|
52
|
+
</Provider>,
|
|
53
|
+
)
|
|
54
|
+
const after = store.getState()
|
|
55
|
+
expect(after.rawFormatter).toBe(fmtB)
|
|
56
|
+
// Formatter is still the percent formatter (re-applied via the effect).
|
|
57
|
+
expect(after.formatter).not.toBe(fmtB)
|
|
58
|
+
expect(after.formatter).toBe(beforePercent)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('initialEnabled=false leaves formatter equal to rawFormatter', () => {
|
|
62
|
+
render(
|
|
63
|
+
<Provider id='rd4' data={[]} formatter={fmtA}>
|
|
64
|
+
<RelativeData initialEnabled={false} />
|
|
65
|
+
</Provider>,
|
|
66
|
+
)
|
|
67
|
+
const s = getWidgetStore('rd4').getState()
|
|
68
|
+
expect(s.formatter).toBe(s.rawFormatter)
|
|
69
|
+
expect(s.formatter).toBe(fmtA)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { useEffect, useMemo, type ComponentType } from 'react'
|
|
2
|
+
import { IconButton, type SvgIconProps } from '@mui/material'
|
|
3
|
+
import PercentIcon from '@mui/icons-material/Percent'
|
|
4
|
+
import { Tooltip } from '../../../components'
|
|
5
|
+
import {
|
|
6
|
+
getWidgetStore,
|
|
7
|
+
useSingleTransform,
|
|
8
|
+
useWidget,
|
|
9
|
+
useWidgetId,
|
|
10
|
+
} from '../../stores'
|
|
11
|
+
import { createPercentFormatter, toRelativeData } from './transforms'
|
|
12
|
+
import { DEFAULT_RELATIVE_DATA_LABELS, type RelativeDataLabels } from './labels'
|
|
13
|
+
import { styles } from './style'
|
|
14
|
+
|
|
15
|
+
const DATA_DESCRIPTOR = {
|
|
16
|
+
id: 'relative-data',
|
|
17
|
+
type: 'data' as const,
|
|
18
|
+
order: 15,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface RelativeDataProps {
|
|
22
|
+
initialEnabled?: boolean
|
|
23
|
+
/**
|
|
24
|
+
* BCP-47 locale tag forwarded to `Intl.NumberFormat`. Defaults to the
|
|
25
|
+
* runtime locale.
|
|
26
|
+
*/
|
|
27
|
+
locale?: string
|
|
28
|
+
labels?: Partial<RelativeDataLabels>
|
|
29
|
+
icon?: ComponentType<SvgIconProps>
|
|
30
|
+
iconProps?: SvgIconProps
|
|
31
|
+
/**
|
|
32
|
+
* Data-side transform that rewrites the widget's series into their
|
|
33
|
+
* relative (0–100) form. Defaults to {@link toRelativeData}, which
|
|
34
|
+
* handles the canonical `{ name, value }[]` shape (bar / pie /
|
|
35
|
+
* timeseries / category). Widgets with a different data shape pass
|
|
36
|
+
* their own — `toRelativeHistogramData` for histogram's `number[]`,
|
|
37
|
+
* `toRelativeScatterplotData` for scatter's `[x, y][]`.
|
|
38
|
+
*
|
|
39
|
+
* Should be a stable top-level reference; inline `(data) => ...`
|
|
40
|
+
* literals re-register the transform every render.
|
|
41
|
+
*/
|
|
42
|
+
transform?: (data: unknown) => unknown
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Toggle between absolute and relative (percentage) values.
|
|
47
|
+
*
|
|
48
|
+
* - **Data side**: a single data transform ({@link toRelativeData}) registered
|
|
49
|
+
* through `useSingleTransform`. When disabled, the pipeline skips it and the
|
|
50
|
+
* derived `data` reverts to `rawData` automatically.
|
|
51
|
+
* - **Formatter side**: an effect writes directly to `state.formatter`. When
|
|
52
|
+
* enabled it installs the Intl-based percent formatter; when disabled it
|
|
53
|
+
* reads `state.rawFormatter` (the consumer-supplied original, always live)
|
|
54
|
+
* and writes it back to `formatter`. No "original" snapshot is captured —
|
|
55
|
+
* `rawFormatter` is the original.
|
|
56
|
+
*/
|
|
57
|
+
export function RelativeData({
|
|
58
|
+
initialEnabled = false,
|
|
59
|
+
locale,
|
|
60
|
+
labels,
|
|
61
|
+
icon: Icon = PercentIcon,
|
|
62
|
+
iconProps,
|
|
63
|
+
transform,
|
|
64
|
+
}: RelativeDataProps) {
|
|
65
|
+
const id = useWidgetId()
|
|
66
|
+
const _labels = { ...DEFAULT_RELATIVE_DATA_LABELS, ...labels }
|
|
67
|
+
|
|
68
|
+
const { enabled, toggle } = useSingleTransform(
|
|
69
|
+
id,
|
|
70
|
+
DATA_DESCRIPTOR,
|
|
71
|
+
transform ?? toRelativeData,
|
|
72
|
+
{ initialEnabled },
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
const percentFormatter = useMemo(
|
|
76
|
+
() => createPercentFormatter(locale),
|
|
77
|
+
[locale],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
// Subscribe to rawFormatter so the effect re-runs and re-applies after the
|
|
81
|
+
// consumer's formatter prop changes (Provider syncs the new prop to both
|
|
82
|
+
// rawFormatter and formatter — re-applying restores the percent override
|
|
83
|
+
// when relative is on, and tracks the new rawFormatter when off).
|
|
84
|
+
const rawFormatter = useWidget(id, (s) => s.rawFormatter)
|
|
85
|
+
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
getWidgetStore(id).setState({
|
|
88
|
+
formatter: enabled ? percentFormatter : rawFormatter,
|
|
89
|
+
})
|
|
90
|
+
}, [id, enabled, percentFormatter, rawFormatter])
|
|
91
|
+
|
|
92
|
+
const tooltip = enabled ? _labels.on : _labels.off
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<Tooltip title={tooltip}>
|
|
96
|
+
<IconButton
|
|
97
|
+
size='small'
|
|
98
|
+
aria-label={tooltip}
|
|
99
|
+
aria-pressed={enabled}
|
|
100
|
+
onClick={toggle}
|
|
101
|
+
sx={{ ...styles.toggle, ...(enabled && styles.toggleActive) }}
|
|
102
|
+
>
|
|
103
|
+
<Icon fontSize='small' {...iconProps} />
|
|
104
|
+
</IconButton>
|
|
105
|
+
</Tooltip>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
} satisfies Record<string, SxProps<Theme>>
|
|
@@ -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
|
+
}
|