@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,200 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
import { describe, it, expect } from 'vitest'
|
|
3
|
+
import { fireEvent, render, screen } from '@testing-library/react'
|
|
4
|
+
import { IconButton } from '@mui/material'
|
|
5
|
+
import StarIcon from '@mui/icons-material/Star'
|
|
6
|
+
import { Toolbox } from './toolbox'
|
|
7
|
+
|
|
8
|
+
function makeChildren(n: number) {
|
|
9
|
+
return Array.from({ length: n }).map((_, i) => (
|
|
10
|
+
<IconButton key={i} aria-label={`Tool ${i + 1}`} size='small'>
|
|
11
|
+
<StarIcon fontSize='small' />
|
|
12
|
+
</IconButton>
|
|
13
|
+
))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Visible iff the item's Toolbox wrapper has `data-toolbox-item-visible`
|
|
18
|
+
* set to `'true'`. Items always mount (single-mount via portal) —
|
|
19
|
+
* visibility is the only thing that flips when the popper opens/closes.
|
|
20
|
+
*/
|
|
21
|
+
function isItemVisible(label: string): boolean {
|
|
22
|
+
const el = screen.getByLabelText(label)
|
|
23
|
+
const wrapper = el.closest('[data-toolbox-item-visible]')
|
|
24
|
+
if (!wrapper) throw new Error(`No toolbox wrapper for "${label}"`)
|
|
25
|
+
return wrapper.getAttribute('data-toolbox-item-visible') === 'true'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe('<Toolbox>', () => {
|
|
29
|
+
it('renders nothing when there are no children', () => {
|
|
30
|
+
const { container } = render(<Toolbox>{null}</Toolbox>)
|
|
31
|
+
expect(container.firstChild).toBeNull()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('renders every child inline when visibleCount is omitted', () => {
|
|
35
|
+
render(<Toolbox>{makeChildren(4)}</Toolbox>)
|
|
36
|
+
for (let i = 1; i <= 4; i++) {
|
|
37
|
+
expect(screen.getByLabelText(`Tool ${i}`)).toBeTruthy()
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('renders every child inline when count <= visibleCount', () => {
|
|
42
|
+
render(<Toolbox visibleCount={5}>{makeChildren(3)}</Toolbox>)
|
|
43
|
+
expect(screen.queryByLabelText('More actions')).toBeNull()
|
|
44
|
+
expect(screen.getByLabelText('Tool 1')).toBeTruthy()
|
|
45
|
+
expect(screen.getByLabelText('Tool 3')).toBeTruthy()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('closed with overflow → first N visible inline, rest in DOM but hidden', () => {
|
|
49
|
+
render(<Toolbox visibleCount={2}>{makeChildren(5)}</Toolbox>)
|
|
50
|
+
// Every item is mounted exactly once.
|
|
51
|
+
for (let i = 1; i <= 5; i++) {
|
|
52
|
+
expect(screen.getAllByLabelText(`Tool ${i}`).length).toBe(1)
|
|
53
|
+
}
|
|
54
|
+
// Visibility: first 2 visible, rest display:none.
|
|
55
|
+
expect(isItemVisible('Tool 1')).toBe(true)
|
|
56
|
+
expect(isItemVisible('Tool 2')).toBe(true)
|
|
57
|
+
expect(isItemVisible('Tool 3')).toBe(false)
|
|
58
|
+
expect(isItemVisible('Tool 4')).toBe(false)
|
|
59
|
+
expect(isItemVisible('Tool 5')).toBe(false)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('open with overflow → all items visible (popover) without remounting any of them', () => {
|
|
63
|
+
let mountCount = 0
|
|
64
|
+
function Counted() {
|
|
65
|
+
const counted = useRef(false)
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (counted.current) return
|
|
68
|
+
counted.current = true
|
|
69
|
+
mountCount += 1
|
|
70
|
+
}, [])
|
|
71
|
+
return (
|
|
72
|
+
<IconButton aria-label='Counted' size='small'>
|
|
73
|
+
<StarIcon fontSize='small' />
|
|
74
|
+
</IconButton>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
render(
|
|
78
|
+
<Toolbox visibleCount={1}>
|
|
79
|
+
<IconButton aria-label='Visible' size='small' key='v'>
|
|
80
|
+
<StarIcon fontSize='small' />
|
|
81
|
+
</IconButton>
|
|
82
|
+
<Counted key='c' />
|
|
83
|
+
</Toolbox>,
|
|
84
|
+
)
|
|
85
|
+
expect(mountCount).toBe(1)
|
|
86
|
+
expect(isItemVisible('Counted')).toBe(false)
|
|
87
|
+
fireEvent.click(screen.getByLabelText('More actions'))
|
|
88
|
+
// Still mounted exactly once — no remount on open.
|
|
89
|
+
expect(mountCount).toBe(1)
|
|
90
|
+
expect(isItemVisible('Counted')).toBe(true)
|
|
91
|
+
fireEvent.click(screen.getByLabelText('Close'))
|
|
92
|
+
// And still no remount on close.
|
|
93
|
+
expect(mountCount).toBe(1)
|
|
94
|
+
expect(isItemVisible('Counted')).toBe(false)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('swaps the trigger label to "Close" when the Paper is open', () => {
|
|
98
|
+
render(<Toolbox visibleCount={2}>{makeChildren(4)}</Toolbox>)
|
|
99
|
+
const trigger = screen.getByLabelText('More actions')
|
|
100
|
+
expect(trigger.getAttribute('aria-pressed')).toBe('false')
|
|
101
|
+
fireEvent.click(trigger)
|
|
102
|
+
// Same button now exposes the close label.
|
|
103
|
+
expect(screen.getByLabelText('Close')).toBe(trigger)
|
|
104
|
+
expect(trigger.getAttribute('aria-pressed')).toBe('true')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('honors a custom trigger label', () => {
|
|
108
|
+
render(
|
|
109
|
+
<Toolbox visibleCount={1} labels={{ trigger: 'Extra' }}>
|
|
110
|
+
{makeChildren(3)}
|
|
111
|
+
</Toolbox>,
|
|
112
|
+
)
|
|
113
|
+
expect(screen.getByLabelText('Extra')).toBeTruthy()
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('keeps a hidden marker between visible items in the inline preview', () => {
|
|
117
|
+
render(
|
|
118
|
+
<Toolbox visibleCount={2}>
|
|
119
|
+
<IconButton key='a' aria-label='Tool A' size='small'>
|
|
120
|
+
<StarIcon fontSize='small' />
|
|
121
|
+
</IconButton>
|
|
122
|
+
<span data-toolbar-hidden key='divider' aria-label='Divider' />
|
|
123
|
+
<IconButton key='b' aria-label='Tool B' size='small'>
|
|
124
|
+
<StarIcon fontSize='small' />
|
|
125
|
+
</IconButton>
|
|
126
|
+
<IconButton key='c' aria-label='Tool C' size='small'>
|
|
127
|
+
<StarIcon fontSize='small' />
|
|
128
|
+
</IconButton>
|
|
129
|
+
</Toolbox>,
|
|
130
|
+
)
|
|
131
|
+
// Every item is mounted exactly once. Inline visibility: A, divider, B
|
|
132
|
+
// (divider sits between visible items); Tool C is hidden inline.
|
|
133
|
+
expect(screen.getAllByLabelText('Tool A').length).toBe(1)
|
|
134
|
+
expect(screen.getAllByLabelText('Divider').length).toBe(1)
|
|
135
|
+
expect(screen.getAllByLabelText('Tool B').length).toBe(1)
|
|
136
|
+
expect(screen.getAllByLabelText('Tool C').length).toBe(1)
|
|
137
|
+
expect(isItemVisible('Tool A')).toBe(true)
|
|
138
|
+
expect(isItemVisible('Divider')).toBe(true)
|
|
139
|
+
expect(isItemVisible('Tool B')).toBe(true)
|
|
140
|
+
expect(isItemVisible('Tool C')).toBe(false)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('drops trailing hidden items past the visible budget — no orphan dividers inline', () => {
|
|
144
|
+
render(
|
|
145
|
+
<Toolbox visibleCount={2}>
|
|
146
|
+
<IconButton key='a' aria-label='Tool A' size='small'>
|
|
147
|
+
<StarIcon fontSize='small' />
|
|
148
|
+
</IconButton>
|
|
149
|
+
<IconButton key='b' aria-label='Tool B' size='small'>
|
|
150
|
+
<StarIcon fontSize='small' />
|
|
151
|
+
</IconButton>
|
|
152
|
+
<span
|
|
153
|
+
data-toolbar-hidden
|
|
154
|
+
key='divider'
|
|
155
|
+
data-testid='trailing-divider'
|
|
156
|
+
/>
|
|
157
|
+
<IconButton key='c' aria-label='Tool C' size='small'>
|
|
158
|
+
<StarIcon fontSize='small' />
|
|
159
|
+
</IconButton>
|
|
160
|
+
</Toolbox>,
|
|
161
|
+
)
|
|
162
|
+
// Inline visibility: A + B; the trailing divider is dropped from the
|
|
163
|
+
// inline-visible set so it doesn't appear as an orphan separator.
|
|
164
|
+
expect(isItemVisible('Tool A')).toBe(true)
|
|
165
|
+
expect(isItemVisible('Tool B')).toBe(true)
|
|
166
|
+
const divider = screen.getByTestId('trailing-divider')
|
|
167
|
+
const wrapper = divider.closest('[data-toolbox-item-visible]')
|
|
168
|
+
expect(wrapper?.getAttribute('data-toolbox-item-visible')).toBe('false')
|
|
169
|
+
expect(isItemVisible('Tool C')).toBe(false)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('marks the trigger active (className) while the Paper is open so the wrapper hover-fade keeps it visible', () => {
|
|
173
|
+
render(<Toolbox visibleCount={2}>{makeChildren(4)}</Toolbox>)
|
|
174
|
+
const trigger = screen.getByLabelText('More actions')
|
|
175
|
+
expect(trigger.className).not.toMatch(/\bactive\b/)
|
|
176
|
+
fireEvent.click(trigger)
|
|
177
|
+
expect(trigger.className).toMatch(/\bactive\b/)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('auto-closes and falls back to inline when visibleCount flips to undefined while the popper is open', () => {
|
|
181
|
+
function Wrap({ count }: { count: number | undefined }) {
|
|
182
|
+
return <Toolbox visibleCount={count}>{makeChildren(5)}</Toolbox>
|
|
183
|
+
}
|
|
184
|
+
const { rerender } = render(<Wrap count={2} />)
|
|
185
|
+
fireEvent.click(screen.getByLabelText('More actions'))
|
|
186
|
+
// Popper open, all items visible inside it.
|
|
187
|
+
for (let i = 1; i <= 5; i++) {
|
|
188
|
+
expect(isItemVisible(`Tool ${i}`)).toBe(true)
|
|
189
|
+
}
|
|
190
|
+
// Caller drops `visibleCount` (e.g. fullscreen opens). Overflow vanishes
|
|
191
|
+
// and so does the popper — items should keep showing inline, *not* be
|
|
192
|
+
// stranded in the detached paper node.
|
|
193
|
+
rerender(<Wrap count={undefined} />)
|
|
194
|
+
expect(screen.queryByLabelText('More actions')).toBeNull()
|
|
195
|
+
expect(screen.queryByLabelText('Close')).toBeNull()
|
|
196
|
+
for (let i = 1; i <= 5; i++) {
|
|
197
|
+
expect(isItemVisible(`Tool ${i}`)).toBe(true)
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
})
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
isValidElement,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useState,
|
|
9
|
+
type ComponentType,
|
|
10
|
+
type ReactElement,
|
|
11
|
+
type ReactNode,
|
|
12
|
+
} from 'react'
|
|
13
|
+
import { createPortal } from 'react-dom'
|
|
14
|
+
import {
|
|
15
|
+
Box,
|
|
16
|
+
Divider,
|
|
17
|
+
Grow,
|
|
18
|
+
IconButton,
|
|
19
|
+
Paper,
|
|
20
|
+
Popper,
|
|
21
|
+
type SvgIconProps,
|
|
22
|
+
type SxProps,
|
|
23
|
+
type Theme,
|
|
24
|
+
} from '@mui/material'
|
|
25
|
+
import CloseIcon from '@mui/icons-material/Close'
|
|
26
|
+
import { WidgetOptions } from '@carto/meridian-ds/custom-icons'
|
|
27
|
+
import { Tooltip } from '../../components'
|
|
28
|
+
import { DEFAULT_TOOLBOX_LABELS, type ToolboxLabels } from './labels'
|
|
29
|
+
import { styles } from './style'
|
|
30
|
+
|
|
31
|
+
export interface ToolboxProps {
|
|
32
|
+
/**
|
|
33
|
+
* Maximum number of (non-`data-toolbar-hidden`) children rendered inline
|
|
34
|
+
* when collapsed. Excess children are revealed via the overflow trigger
|
|
35
|
+
* inside a floating Paper. When omitted, all children render inline.
|
|
36
|
+
*/
|
|
37
|
+
visibleCount?: number
|
|
38
|
+
labels?: Partial<ToolboxLabels>
|
|
39
|
+
/**
|
|
40
|
+
* Glyph used for the closed-state trigger. Defaults to the meridian-ds
|
|
41
|
+
* `WidgetOptions` icon (matches v1's `ToolbarActions`).
|
|
42
|
+
*/
|
|
43
|
+
icon?: ComponentType<SvgIconProps>
|
|
44
|
+
iconProps?: SvgIconProps
|
|
45
|
+
/**
|
|
46
|
+
* Side the overflow Paper opens toward. `'right'` (default) places the
|
|
47
|
+
* trigger on the left and the Paper covers the row to the right;
|
|
48
|
+
* `'left'` is the mirror.
|
|
49
|
+
*/
|
|
50
|
+
direction?: 'left' | 'right'
|
|
51
|
+
sx?: SxProps<Theme>
|
|
52
|
+
children: ReactNode
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Smart overflow toolbar with **single-mount** items. Children mount once
|
|
57
|
+
* into a stable, hidden host element and are *physically reparented* via
|
|
58
|
+
* `appendChild` between the inline preview area and the overflow `<Paper>`
|
|
59
|
+
* as the popper opens / closes — same pattern as `Widget.FullScreen.Slot`.
|
|
60
|
+
* Items with no inline space when closed are kept mounted but visually
|
|
61
|
+
* hidden via `display: none`.
|
|
62
|
+
*
|
|
63
|
+
* Why this matters: every toggle's `useTransform` registers a config /
|
|
64
|
+
* data transform on mount and removes it on unmount. If items remounted
|
|
65
|
+
* on each open / close, the brief setup → cleanup window would re-emit
|
|
66
|
+
* the pipeline (transform missing → transform present), causing a visible
|
|
67
|
+
* flicker on state-bearing transforms (Stack, Zoom, RelativeData). With
|
|
68
|
+
* stable mounts the transform stays registered across the whole popover
|
|
69
|
+
* lifecycle.
|
|
70
|
+
*
|
|
71
|
+
* Children flagged with `data-toolbar-hidden` (e.g. dividers) skip the
|
|
72
|
+
* visibility budget but still render in their natural position. Trailing
|
|
73
|
+
* hidden items past the budget are excluded from the inline preview so
|
|
74
|
+
* they don't appear as orphan separators in the inline row; they're still
|
|
75
|
+
* there in the popover.
|
|
76
|
+
*/
|
|
77
|
+
export function Toolbox({
|
|
78
|
+
visibleCount,
|
|
79
|
+
labels,
|
|
80
|
+
icon: Icon = WidgetOptions,
|
|
81
|
+
iconProps,
|
|
82
|
+
direction = 'right',
|
|
83
|
+
sx,
|
|
84
|
+
children,
|
|
85
|
+
}: ToolboxProps) {
|
|
86
|
+
const _labels = { ...DEFAULT_TOOLBOX_LABELS, ...labels }
|
|
87
|
+
// Each useState below is independent UI state — not "related state" that
|
|
88
|
+
// `useReducer` would clean up. Justifications:
|
|
89
|
+
// - `open`: toggles the overflow popover, drives JSX rendering.
|
|
90
|
+
// - `anchorEl`: feeds `<Popper anchorEl>`; the Popper must re-render
|
|
91
|
+
// when the trigger element first attaches.
|
|
92
|
+
// - `inlineEl` / `paperEl`: read by the layout-effect dep array below
|
|
93
|
+
// to reparent the stable host between shells; useRef wouldn't fire
|
|
94
|
+
// the effect when the elements attach.
|
|
95
|
+
// - `host` (further down): see its own comment — kept in state to make
|
|
96
|
+
// the React Compiler happy reading it during render.
|
|
97
|
+
const [open, setOpen] = useState(false)
|
|
98
|
+
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null)
|
|
99
|
+
const [inlineEl, setInlineEl] = useState<HTMLElement | null>(null)
|
|
100
|
+
const [paperEl, setPaperEl] = useState<HTMLElement | null>(null)
|
|
101
|
+
|
|
102
|
+
const handleToggle = useCallback(() => setOpen((v) => !v), [])
|
|
103
|
+
const handleTriggerRef = useCallback((node: HTMLButtonElement | null) => {
|
|
104
|
+
setAnchorEl(node)
|
|
105
|
+
}, [])
|
|
106
|
+
|
|
107
|
+
// Esc closes the overflow paper. Outside-click is intentionally NOT wired:
|
|
108
|
+
// an action inside the Paper (e.g. RelativeData toggling, a Brush menu)
|
|
109
|
+
// can update widget state which momentarily reflows the page; if that's
|
|
110
|
+
// treated as a click-outside, the Paper would dismiss itself mid-action.
|
|
111
|
+
// Users explicitly close via the trigger or Escape.
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (!open) return undefined
|
|
114
|
+
const onKey = (e: KeyboardEvent) => {
|
|
115
|
+
if (e.key === 'Escape') setOpen(false)
|
|
116
|
+
}
|
|
117
|
+
document.addEventListener('keydown', onKey)
|
|
118
|
+
return () => document.removeEventListener('keydown', onKey)
|
|
119
|
+
}, [open])
|
|
120
|
+
|
|
121
|
+
// Stable host element shared by every toolbox cycle. `display: contents`
|
|
122
|
+
// keeps it transparent in flow so items inherit layout (flex row + gap)
|
|
123
|
+
// from whichever shell currently parents the host (the inline preview
|
|
124
|
+
// Box or the popover Paper). Held in state — not a ref — so the React
|
|
125
|
+
// Compiler is happy reading it during render.
|
|
126
|
+
const [host] = useState<HTMLDivElement | null>(() => {
|
|
127
|
+
if (typeof document === 'undefined') return null
|
|
128
|
+
const div = document.createElement('div')
|
|
129
|
+
div.style.display = 'contents'
|
|
130
|
+
return div
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const items = Children.toArray(children).filter((c): c is ReactElement =>
|
|
134
|
+
isValidElement(c),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
const visibleCountActual = items.reduce(
|
|
138
|
+
(n, c) => n + (isToolbarHidden(c) ? 0 : 1),
|
|
139
|
+
0,
|
|
140
|
+
)
|
|
141
|
+
const showOverflow =
|
|
142
|
+
visibleCount !== undefined && visibleCountActual > visibleCount
|
|
143
|
+
|
|
144
|
+
// Indices that are visible inline when the popper is closed. When the
|
|
145
|
+
// popper is open, every item is visible (in the popover). `null` means
|
|
146
|
+
// "no overflow — all items visible inline".
|
|
147
|
+
const inlineVisibleIndices = useMemo<Set<number> | null>(() => {
|
|
148
|
+
if (!showOverflow || visibleCount === undefined) return null
|
|
149
|
+
return computeInlineVisibleIndices(items, visibleCount)
|
|
150
|
+
}, [items, visibleCount, showOverflow])
|
|
151
|
+
|
|
152
|
+
// Auto-close the popper when overflow disappears (e.g. `visibleCount`
|
|
153
|
+
// flips from a number to `undefined` because the consumer entered
|
|
154
|
+
// fullscreen and wants every action visible inline). Without this the
|
|
155
|
+
// popper component unmounts under us, `paperEl` goes null, and the host
|
|
156
|
+
// would be stranded in a detached node — the toolbox visibly disappears.
|
|
157
|
+
//
|
|
158
|
+
// Uses React's documented "store information from previous renders"
|
|
159
|
+
// pattern: a guarded inline `setOpen(false)` during render. The guard
|
|
160
|
+
// fires at most once per transition (`open` flips false the same render
|
|
161
|
+
// and the next render's predicate is false). React rebases the in-flight
|
|
162
|
+
// render before commit, so the layout effect below sees `open=false`
|
|
163
|
+
// immediately. See
|
|
164
|
+
// https://react.dev/reference/react/useState#storing-information-from-previous-renders
|
|
165
|
+
if (!showOverflow && open) {
|
|
166
|
+
setOpen(false)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Reparent the host into the active shell whenever `open` (or either
|
|
170
|
+
// shell) changes. `useLayoutEffect` runs synchronously after commit
|
|
171
|
+
// (after refs have been written), so the popover Paper ref is already
|
|
172
|
+
// live when we read it. Falling back to `inlineEl` whenever `paperEl`
|
|
173
|
+
// is missing handles cases where the popper has unmounted (showOverflow
|
|
174
|
+
// flipped false) — the host always has a valid destination.
|
|
175
|
+
useLayoutEffect(() => {
|
|
176
|
+
const target = open && paperEl ? paperEl : inlineEl
|
|
177
|
+
if (host && target && host.parentNode !== target) {
|
|
178
|
+
target.appendChild(host)
|
|
179
|
+
}
|
|
180
|
+
}, [open, inlineEl, paperEl, host])
|
|
181
|
+
|
|
182
|
+
if (items.length === 0) return null
|
|
183
|
+
|
|
184
|
+
const tooltipLabel = open ? _labels.close : _labels.trigger
|
|
185
|
+
const flexDirection = direction === 'left' ? 'row-reverse' : 'row'
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<Box sx={{ ...styles.root, flexDirection, ...sx }}>
|
|
189
|
+
{showOverflow && (
|
|
190
|
+
<>
|
|
191
|
+
<Tooltip title={tooltipLabel}>
|
|
192
|
+
<IconButton
|
|
193
|
+
ref={handleTriggerRef}
|
|
194
|
+
size='small'
|
|
195
|
+
aria-label={tooltipLabel}
|
|
196
|
+
aria-pressed={open}
|
|
197
|
+
onClick={handleToggle}
|
|
198
|
+
className={open ? 'active' : undefined}
|
|
199
|
+
sx={{ ...(open && styles.triggerActive) }}
|
|
200
|
+
>
|
|
201
|
+
{open ? (
|
|
202
|
+
<CloseIcon fontSize='small' />
|
|
203
|
+
) : (
|
|
204
|
+
<Icon fontSize='small' {...iconProps} />
|
|
205
|
+
)}
|
|
206
|
+
</IconButton>
|
|
207
|
+
</Tooltip>
|
|
208
|
+
<Divider orientation='vertical' flexItem sx={{ mx: 0.5 }} />
|
|
209
|
+
</>
|
|
210
|
+
)}
|
|
211
|
+
|
|
212
|
+
{/* Inline shell: when closed (or when there's no overflow) the host
|
|
213
|
+
lives here so first-N items appear inline beside the trigger. */}
|
|
214
|
+
<Box ref={setInlineEl} sx={styles.preview} />
|
|
215
|
+
|
|
216
|
+
{showOverflow && (
|
|
217
|
+
<Popper
|
|
218
|
+
open={open}
|
|
219
|
+
anchorEl={anchorEl}
|
|
220
|
+
placement={direction === 'left' ? 'left' : 'right'}
|
|
221
|
+
transition
|
|
222
|
+
// Disable flipping so the Paper stays on the configured side
|
|
223
|
+
// even when the trigger sits near a viewport edge — wrapper
|
|
224
|
+
// consumers expect a stable layout.
|
|
225
|
+
modifiers={[{ name: 'flip', enabled: false }]}
|
|
226
|
+
// Slot the popper *above* most modal stacking, but below MUI's
|
|
227
|
+
// own modal layer.
|
|
228
|
+
sx={{ zIndex: 'tooltip', mt: 0 }}
|
|
229
|
+
>
|
|
230
|
+
{({ TransitionProps }) => (
|
|
231
|
+
<Grow
|
|
232
|
+
{...TransitionProps}
|
|
233
|
+
style={{
|
|
234
|
+
transformOrigin:
|
|
235
|
+
direction === 'left' ? 'right center' : 'left center',
|
|
236
|
+
}}
|
|
237
|
+
>
|
|
238
|
+
<Paper ref={setPaperEl} sx={styles.paper} />
|
|
239
|
+
</Grow>
|
|
240
|
+
)}
|
|
241
|
+
</Popper>
|
|
242
|
+
)}
|
|
243
|
+
|
|
244
|
+
{/* Items render once into the stable host. The host's parent is
|
|
245
|
+
whichever shell is currently active (inline or popper). When
|
|
246
|
+
closed-with-overflow, items beyond the budget get `display: none`
|
|
247
|
+
so they're mounted but invisible. The wrapper uses an inline
|
|
248
|
+
`style` (not `sx`) so the visibility decision lands on the
|
|
249
|
+
element itself — tests can inspect it without traversing
|
|
250
|
+
generated MUI class names. */}
|
|
251
|
+
{host
|
|
252
|
+
? createPortal(
|
|
253
|
+
items.map((item, i) => {
|
|
254
|
+
const visible =
|
|
255
|
+
open || !inlineVisibleIndices || inlineVisibleIndices.has(i)
|
|
256
|
+
const key = item.key ?? i
|
|
257
|
+
return (
|
|
258
|
+
<div
|
|
259
|
+
key={key}
|
|
260
|
+
data-toolbox-item-visible={visible ? 'true' : 'false'}
|
|
261
|
+
style={{ display: visible ? 'contents' : 'none' }}
|
|
262
|
+
>
|
|
263
|
+
{item}
|
|
264
|
+
</div>
|
|
265
|
+
)
|
|
266
|
+
}),
|
|
267
|
+
host,
|
|
268
|
+
)
|
|
269
|
+
: null}
|
|
270
|
+
</Box>
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function isToolbarHidden(child: ReactElement): boolean {
|
|
275
|
+
// Opt-in flag callers set on slot children (e.g. dividers between groups)
|
|
276
|
+
// so they don't count toward the inline visibility budget.
|
|
277
|
+
const props = (
|
|
278
|
+
child as unknown as { props: { 'data-toolbar-hidden'?: unknown } }
|
|
279
|
+
).props
|
|
280
|
+
return props['data-toolbar-hidden'] === true
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Compute the set of item indices visible inline when the popper is closed.
|
|
285
|
+
* Walk the items in order, accept each one until the visible budget is
|
|
286
|
+
* exhausted; hidden items (dividers, etc.) accept without bumping the
|
|
287
|
+
* counter. Strip trailing hidden items from the visible set so the inline
|
|
288
|
+
* row doesn't end with an orphan separator.
|
|
289
|
+
*/
|
|
290
|
+
function computeInlineVisibleIndices(
|
|
291
|
+
items: readonly ReactElement[],
|
|
292
|
+
visibleCount: number,
|
|
293
|
+
): Set<number> {
|
|
294
|
+
const indices: number[] = []
|
|
295
|
+
let count = 0
|
|
296
|
+
for (let i = 0; i < items.length; i++) {
|
|
297
|
+
if (count >= visibleCount) break
|
|
298
|
+
indices.push(i)
|
|
299
|
+
if (!isToolbarHidden(items[i]!)) count++
|
|
300
|
+
}
|
|
301
|
+
// Strip trailing hidden items.
|
|
302
|
+
while (
|
|
303
|
+
indices.length > 0 &&
|
|
304
|
+
isToolbarHidden(items[indices[indices.length - 1]!]!)
|
|
305
|
+
) {
|
|
306
|
+
indices.pop()
|
|
307
|
+
}
|
|
308
|
+
return new Set(indices)
|
|
309
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ZOOM_LAYOUT } from '../actions/zoom-toggle'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* If the option includes a `dataZoom` array (from ZoomToggle's transform),
|
|
5
|
+
* lift any slider entries above the legend row so they don't overlap.
|
|
6
|
+
* Returns `null` when there is no `dataZoom` — caller skips the layout
|
|
7
|
+
* adjustment entirely.
|
|
8
|
+
*
|
|
9
|
+
* Shared between bar, histogram, and timeseries — every widget with a
|
|
10
|
+
* horizontal x-axis dataZoom slider needs the same offset when a legend
|
|
11
|
+
* is rendered below the plot.
|
|
12
|
+
*/
|
|
13
|
+
export function positionDataZoomForLegend(
|
|
14
|
+
dataZoom: unknown,
|
|
15
|
+
hasLegend: boolean,
|
|
16
|
+
): unknown[] | null {
|
|
17
|
+
if (!Array.isArray(dataZoom) || dataZoom.length === 0) return null
|
|
18
|
+
return dataZoom.map((entry: unknown) => {
|
|
19
|
+
if (entry == null || typeof entry !== 'object') return entry
|
|
20
|
+
const dz = entry as { type?: string; bottom?: number }
|
|
21
|
+
if (dz.type === 'slider' && hasLegend) {
|
|
22
|
+
return { ...dz, bottom: ZOOM_LAYOUT.sliderBottomWithLegend }
|
|
23
|
+
}
|
|
24
|
+
return dz
|
|
25
|
+
})
|
|
26
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mergeOptions } from './merge-options'
|
|
3
|
+
|
|
4
|
+
describe('mergeOptions', () => {
|
|
5
|
+
it('returns base unchanged when override is undefined', () => {
|
|
6
|
+
const base = { a: 1, b: { c: 2 } }
|
|
7
|
+
expect(mergeOptions(base)).toBe(base)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('shallow-merges top-level keys', () => {
|
|
11
|
+
const base: Record<string, unknown> = { a: 1, b: 2 }
|
|
12
|
+
const out = mergeOptions(base, { b: 3, c: 4 })
|
|
13
|
+
expect(out).toEqual({ a: 1, b: 3, c: 4 })
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('shallow-merges plain objects per key', () => {
|
|
17
|
+
const base: Record<string, unknown> = { x: { p: 1, q: 2 } }
|
|
18
|
+
const out = mergeOptions(base, { x: { q: 99, r: 3 } })
|
|
19
|
+
expect(out).toEqual({ x: { p: 1, q: 99, r: 3 } })
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('merges arrays element-wise, deep-merging plain-object elements', () => {
|
|
23
|
+
const base: Record<string, unknown> = {
|
|
24
|
+
series: [{ type: 'bar', data: [1, 2] }, { type: 'line' }],
|
|
25
|
+
}
|
|
26
|
+
const out = mergeOptions(base, {
|
|
27
|
+
series: [{ data: [3, 4] }, { name: 'second' }],
|
|
28
|
+
})
|
|
29
|
+
expect(out).toEqual({
|
|
30
|
+
series: [
|
|
31
|
+
{ type: 'bar', data: [3, 4] },
|
|
32
|
+
{ type: 'line', name: 'second' },
|
|
33
|
+
],
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('primitive override replaces primitive base', () => {
|
|
38
|
+
expect(mergeOptions({ count: 1 }, { count: 99 })).toEqual({ count: 99 })
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('skips override values that are undefined', () => {
|
|
42
|
+
expect(mergeOptions({ a: 1, b: 2 }, { a: undefined })).toEqual({
|
|
43
|
+
a: 1,
|
|
44
|
+
b: 2,
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('uses base value when array is longer than override', () => {
|
|
49
|
+
const base: Record<string, unknown> = { s: [1, 2, 3] }
|
|
50
|
+
expect(mergeOptions(base, { s: [10] })).toEqual({ s: [10, 2, 3] })
|
|
51
|
+
})
|
|
52
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shallow-merges two ECharts option objects:
|
|
3
|
+
* - Top-level keys from both are combined.
|
|
4
|
+
* - Arrays are merged by index (element-wise shallow merge, primitive override).
|
|
5
|
+
* - Plain objects are shallow-merged.
|
|
6
|
+
* - Primitives are overridden by the override value.
|
|
7
|
+
*
|
|
8
|
+
* Designed for the two-stage memoization pattern: first build a base option
|
|
9
|
+
* object from data + theme + formatters, then call `mergeOptions(base, override)`
|
|
10
|
+
* inside a second `useMemo` keyed on `[base, override]`.
|
|
11
|
+
*/
|
|
12
|
+
export function mergeOptions<T extends Record<string, unknown>>(
|
|
13
|
+
base: T,
|
|
14
|
+
override?: Partial<T>,
|
|
15
|
+
): T {
|
|
16
|
+
if (!override) return base
|
|
17
|
+
const out: Record<string, unknown> = { ...base }
|
|
18
|
+
for (const key of Object.keys(override) as (keyof T)[]) {
|
|
19
|
+
const a = base[key]
|
|
20
|
+
const b = override[key]
|
|
21
|
+
if (b === undefined) continue
|
|
22
|
+
out[key as string] = mergeValue(a, b)
|
|
23
|
+
}
|
|
24
|
+
return out as T
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function mergeValue(a: unknown, b: unknown): unknown {
|
|
28
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
29
|
+
const len = Math.max(a.length, b.length)
|
|
30
|
+
const result = new Array<unknown>(len)
|
|
31
|
+
for (let i = 0; i < len; i++) {
|
|
32
|
+
const av: unknown = a[i]
|
|
33
|
+
const bv: unknown = b[i]
|
|
34
|
+
if (bv === undefined) result[i] = av
|
|
35
|
+
else if (av === undefined) result[i] = bv
|
|
36
|
+
else result[i] = mergeValue(av, bv)
|
|
37
|
+
}
|
|
38
|
+
return result
|
|
39
|
+
}
|
|
40
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
41
|
+
return { ...a, ...b }
|
|
42
|
+
}
|
|
43
|
+
return b
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function isPlainObject(v: unknown): v is Record<string, unknown> {
|
|
47
|
+
if (v === null || typeof v !== 'object') return false
|
|
48
|
+
const proto = Object.getPrototypeOf(v) as unknown
|
|
49
|
+
return proto === Object.prototype || proto === null
|
|
50
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { Wrapper, type WrapperProps } from './widget-wrapper'
|
|
2
|
+
export {
|
|
3
|
+
Actions,
|
|
4
|
+
Options,
|
|
5
|
+
type ActionsProps,
|
|
6
|
+
type OptionsProps,
|
|
7
|
+
} from './widget-actions'
|
|
8
|
+
export {
|
|
9
|
+
Content,
|
|
10
|
+
Footer,
|
|
11
|
+
type ContentProps,
|
|
12
|
+
type FooterProps,
|
|
13
|
+
} from './widget-content'
|
|
14
|
+
export { DEFAULT_WRAPPER_LABELS, type WrapperLabels } from './labels'
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface WrapperLabels {
|
|
2
|
+
collapse: string
|
|
3
|
+
expand: string
|
|
4
|
+
errorFallbackTitle: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const DEFAULT_WRAPPER_LABELS: WrapperLabels = {
|
|
8
|
+
collapse: 'Collapse',
|
|
9
|
+
expand: 'Expand',
|
|
10
|
+
errorFallbackTitle: 'Widget failed to render',
|
|
11
|
+
}
|