@automattic/charts 0.16.2 → 0.18.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/CHANGELOG.md +20 -0
- package/dist/cjs/_virtual/index.js +2 -0
- package/dist/cjs/_virtual/index.js.map +1 -0
- package/dist/cjs/_virtual/react-is.development.js +2 -0
- package/dist/cjs/_virtual/react-is.development.js.map +1 -0
- package/dist/cjs/_virtual/react-is.production.min.js +2 -0
- package/dist/cjs/_virtual/react-is.production.min.js.map +1 -0
- package/dist/cjs/_virtual/sprintf.js +2 -0
- package/dist/cjs/_virtual/sprintf.js.map +1 -0
- package/dist/cjs/components/bar-chart/bar-chart.js +1 -1
- package/dist/cjs/components/bar-chart/bar-chart.js.map +1 -1
- package/dist/cjs/components/bar-chart/use-bar-chart-options.js +1 -1
- package/dist/cjs/components/bar-chart/use-bar-chart-options.js.map +1 -1
- package/dist/cjs/components/bar-list-chart/bar-list-chart.js +1 -1
- package/dist/cjs/components/bar-list-chart/bar-list-chart.js.map +1 -1
- package/dist/cjs/components/leaderboard-chart/leaderboard-chart.js +2 -0
- package/dist/cjs/components/leaderboard-chart/leaderboard-chart.js.map +1 -0
- package/dist/cjs/components/leaderboard-chart/leaderboard-chart.module.scss.js +2 -0
- package/dist/cjs/components/leaderboard-chart/leaderboard-chart.module.scss.js.map +1 -0
- package/dist/cjs/components/legend/base-legend.js +1 -1
- package/dist/cjs/components/legend/base-legend.js.map +1 -1
- package/dist/cjs/components/line-chart/line-chart-annotation-label-popover.js +2 -0
- package/dist/cjs/components/line-chart/line-chart-annotation-label-popover.js.map +1 -0
- package/dist/cjs/components/line-chart/line-chart-annotation.js +1 -1
- package/dist/cjs/components/line-chart/line-chart-annotation.js.map +1 -1
- package/dist/cjs/components/line-chart/line-chart-annotations-overlay.js +2 -0
- package/dist/cjs/components/line-chart/line-chart-annotations-overlay.js.map +1 -0
- package/dist/cjs/components/line-chart/line-chart-context.js +2 -0
- package/dist/cjs/components/line-chart/line-chart-context.js.map +1 -0
- package/dist/cjs/components/line-chart/line-chart.js +1 -1
- package/dist/cjs/components/line-chart/line-chart.js.map +1 -1
- package/dist/cjs/components/line-chart/line-chart.module.scss.js +1 -1
- package/dist/cjs/components/pie-chart/pie-chart.js +1 -1
- package/dist/cjs/components/pie-chart/pie-chart.js.map +1 -1
- package/dist/cjs/components/pie-semi-circle-chart/pie-semi-circle-chart.js +1 -1
- package/dist/cjs/components/pie-semi-circle-chart/pie-semi-circle-chart.js.map +1 -1
- package/dist/cjs/components/shared/format-metric-value.js +2 -0
- package/dist/cjs/components/shared/format-metric-value.js.map +1 -0
- package/dist/cjs/components/shared/use-chart-data-transform.js +1 -1
- package/dist/cjs/components/shared/use-chart-data-transform.js.map +1 -1
- package/dist/cjs/components/shared/use-chart-margin.js +1 -1
- package/dist/cjs/components/shared/use-chart-margin.js.map +1 -1
- package/dist/cjs/components/shared/use-element-height.js +1 -1
- package/dist/cjs/components/shared/use-element-height.js.map +1 -1
- package/dist/cjs/components/shared/utils.js +1 -1
- package/dist/cjs/components/shared/utils.js.map +1 -1
- package/dist/cjs/components/tooltip/accessible-tooltip.js +2 -0
- package/dist/cjs/components/tooltip/accessible-tooltip.js.map +1 -0
- package/dist/cjs/hooks/use-chart-mouse-handler.js +1 -1
- package/dist/cjs/hooks/use-chart-mouse-handler.js.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/node_modules/.pnpm/@emotion_cache@11.14.0/node_modules/@emotion/cache/dist/emotion-cache.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_cache@11.14.0/node_modules/@emotion/cache/dist/emotion-cache.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_hash@0.9.2/node_modules/@emotion/hash/dist/emotion-hash.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_hash@0.9.2/node_modules/@emotion/hash/dist/emotion-hash.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_is-prop-valid@1.3.1/node_modules/@emotion/is-prop-valid/dist/emotion-is-prop-valid.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_is-prop-valid@1.3.1/node_modules/@emotion/is-prop-valid/dist/emotion-is-prop-valid.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_memoize@0.9.0/node_modules/@emotion/memoize/dist/emotion-memoize.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_memoize@0.9.0/node_modules/@emotion/memoize/dist/emotion-memoize.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1/node_modules/@emotion/react/dist/emotion-element-d59e098f.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1/node_modules/@emotion/react/dist/emotion-element-d59e098f.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1/node_modules/@emotion/react/dist/emotion-react.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1/node_modules/@emotion/react/dist/emotion-react.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_serialize@1.3.3/node_modules/@emotion/serialize/dist/emotion-serialize.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_serialize@1.3.3/node_modules/@emotion/serialize/dist/emotion-serialize.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_sheet@1.4.0/node_modules/@emotion/sheet/dist/emotion-sheet.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_sheet@1.4.0/node_modules/@emotion/sheet/dist/emotion-sheet.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_styled@11.14.0_@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1__@types_react@18.3.23_react@18.3.1/node_modules/@emotion/styled/base/dist/emotion-styled-base.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_styled@11.14.0_@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1__@types_react@18.3.23_react@18.3.1/node_modules/@emotion/styled/base/dist/emotion-styled-base.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_unitless@0.10.0/node_modules/@emotion/unitless/dist/emotion-unitless.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_unitless@0.10.0/node_modules/@emotion/unitless/dist/emotion-unitless.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_use-insertion-effect-with-fallbacks@1.2.0_react@18.3.1/node_modules/@emotion/use-insertion-effect-with-fallbacks/dist/emotion-use-insertion-effect-with-fallbacks.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_use-insertion-effect-with-fallbacks@1.2.0_react@18.3.1/node_modules/@emotion/use-insertion-effect-with-fallbacks/dist/emotion-use-insertion-effect-with-fallbacks.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_utils@1.4.2/node_modules/@emotion/utils/dist/emotion-utils.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_utils@1.4.2/node_modules/@emotion/utils/dist/emotion-utils.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_weak-memoize@0.4.0/node_modules/@emotion/weak-memoize/dist/emotion-weak-memoize.esm.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@emotion_weak-memoize@0.4.0/node_modules/@emotion/weak-memoize/dist/emotion-weak-memoize.esm.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@tannin_compile@1.1.0/node_modules/@tannin/compile/index.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@tannin_compile@1.1.0/node_modules/@tannin/compile/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@tannin_evaluate@1.2.0/node_modules/@tannin/evaluate/index.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@tannin_evaluate@1.2.0/node_modules/@tannin/evaluate/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@tannin_plural-forms@1.1.0/node_modules/@tannin/plural-forms/index.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@tannin_plural-forms@1.1.0/node_modules/@tannin/plural-forms/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@tannin_postfix@1.1.0/node_modules/@tannin/postfix/index.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@tannin_postfix@1.1.0/node_modules/@tannin/postfix/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/progress-bar/index.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/progress-bar/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/progress-bar/styles.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/progress-bar/styles.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/colors-values.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/colors-values.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/config-values.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/config-values.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/space.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/space.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createAddHook.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createAddHook.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createCurrentHook.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createCurrentHook.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createDidHook.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createDidHook.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createDoingHook.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createDoingHook.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createHasHook.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createHasHook.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createHooks.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createHooks.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createRemoveHook.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createRemoveHook.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createRunHook.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createRunHook.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/index.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/validateHookName.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/validateHookName.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/validateNamespace.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/validateNamespace.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_i18n@5.26.0/node_modules/@wordpress/i18n/build-module/create-i18n.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_i18n@5.26.0/node_modules/@wordpress/i18n/build-module/create-i18n.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_i18n@5.26.0/node_modules/@wordpress/i18n/build-module/default-i18n.js +2 -0
- package/dist/cjs/node_modules/.pnpm/@wordpress_i18n@5.26.0/node_modules/@wordpress/i18n/build-module/default-i18n.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/hoist-non-react-statics@3.3.2/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js +2 -0
- package/dist/cjs/node_modules/.pnpm/hoist-non-react-statics@3.3.2/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/cjs/react-is.development.js +10 -0
- package/dist/cjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/cjs/react-is.development.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/cjs/react-is.production.min.js +10 -0
- package/dist/cjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/cjs/react-is.production.min.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/index.js +2 -0
- package/dist/cjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/index.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/sprintf-js@1.1.3/node_modules/sprintf-js/src/sprintf.js +2 -0
- package/dist/cjs/node_modules/.pnpm/sprintf-js@1.1.3/node_modules/sprintf-js/src/sprintf.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Enum.js +2 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Enum.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Middleware.js +2 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Middleware.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Parser.js +2 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Parser.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Serializer.js +2 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Serializer.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Tokenizer.js +2 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Tokenizer.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Utility.js +2 -0
- package/dist/cjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Utility.js.map +1 -0
- package/dist/cjs/node_modules/.pnpm/tannin@1.2.0/node_modules/tannin/index.js +2 -0
- package/dist/cjs/node_modules/.pnpm/tannin@1.2.0/node_modules/tannin/index.js.map +1 -0
- package/dist/cjs/providers/chart-context/chart-context.js +2 -0
- package/dist/cjs/providers/chart-context/chart-context.js.map +1 -0
- package/dist/cjs/providers/chart-context/utils.js +2 -0
- package/dist/cjs/providers/chart-context/utils.js.map +1 -0
- package/dist/cjs/providers/theme/theme-provider.js +1 -1
- package/dist/cjs/providers/theme/theme-provider.js.map +1 -1
- package/dist/cjs/style.css +1 -1
- package/dist/index.d.ts +151 -20
- package/dist/mjs/_virtual/index.js +2 -0
- package/dist/mjs/_virtual/index.js.map +1 -0
- package/dist/mjs/_virtual/react-is.development.js +2 -0
- package/dist/mjs/_virtual/react-is.development.js.map +1 -0
- package/dist/mjs/_virtual/react-is.production.min.js +2 -0
- package/dist/mjs/_virtual/react-is.production.min.js.map +1 -0
- package/dist/mjs/_virtual/sprintf.js +2 -0
- package/dist/mjs/_virtual/sprintf.js.map +1 -0
- package/dist/mjs/components/bar-chart/bar-chart.js +1 -1
- package/dist/mjs/components/bar-chart/bar-chart.js.map +1 -1
- package/dist/mjs/components/bar-chart/use-bar-chart-options.js +1 -1
- package/dist/mjs/components/bar-chart/use-bar-chart-options.js.map +1 -1
- package/dist/mjs/components/bar-list-chart/bar-list-chart.js +1 -1
- package/dist/mjs/components/bar-list-chart/bar-list-chart.js.map +1 -1
- package/dist/mjs/components/leaderboard-chart/leaderboard-chart.js +2 -0
- package/dist/mjs/components/leaderboard-chart/leaderboard-chart.js.map +1 -0
- package/dist/mjs/components/leaderboard-chart/leaderboard-chart.module.scss.js +2 -0
- package/dist/mjs/components/leaderboard-chart/leaderboard-chart.module.scss.js.map +1 -0
- package/dist/mjs/components/legend/base-legend.js +1 -1
- package/dist/mjs/components/legend/base-legend.js.map +1 -1
- package/dist/mjs/components/line-chart/line-chart-annotation-label-popover.js +2 -0
- package/dist/mjs/components/line-chart/line-chart-annotation-label-popover.js.map +1 -0
- package/dist/mjs/components/line-chart/line-chart-annotation.js +1 -1
- package/dist/mjs/components/line-chart/line-chart-annotation.js.map +1 -1
- package/dist/mjs/components/line-chart/line-chart-annotations-overlay.js +2 -0
- package/dist/mjs/components/line-chart/line-chart-annotations-overlay.js.map +1 -0
- package/dist/mjs/components/line-chart/line-chart-context.js +2 -0
- package/dist/mjs/components/line-chart/line-chart-context.js.map +1 -0
- package/dist/mjs/components/line-chart/line-chart.js +1 -1
- package/dist/mjs/components/line-chart/line-chart.js.map +1 -1
- package/dist/mjs/components/line-chart/line-chart.module.scss.js +1 -1
- package/dist/mjs/components/pie-chart/pie-chart.js +1 -1
- package/dist/mjs/components/pie-chart/pie-chart.js.map +1 -1
- package/dist/mjs/components/pie-semi-circle-chart/pie-semi-circle-chart.js +1 -1
- package/dist/mjs/components/pie-semi-circle-chart/pie-semi-circle-chart.js.map +1 -1
- package/dist/mjs/components/shared/format-metric-value.js +2 -0
- package/dist/mjs/components/shared/format-metric-value.js.map +1 -0
- package/dist/mjs/components/shared/use-chart-data-transform.js +1 -1
- package/dist/mjs/components/shared/use-chart-data-transform.js.map +1 -1
- package/dist/mjs/components/shared/use-chart-margin.js +1 -1
- package/dist/mjs/components/shared/use-chart-margin.js.map +1 -1
- package/dist/mjs/components/shared/use-element-height.js +1 -1
- package/dist/mjs/components/shared/use-element-height.js.map +1 -1
- package/dist/mjs/components/shared/utils.js +1 -1
- package/dist/mjs/components/shared/utils.js.map +1 -1
- package/dist/mjs/components/tooltip/accessible-tooltip.js +2 -0
- package/dist/mjs/components/tooltip/accessible-tooltip.js.map +1 -0
- package/dist/mjs/hooks/use-chart-mouse-handler.js +1 -1
- package/dist/mjs/hooks/use-chart-mouse-handler.js.map +1 -1
- package/dist/mjs/index.js +1 -1
- package/dist/mjs/node_modules/.pnpm/@emotion_cache@11.14.0/node_modules/@emotion/cache/dist/emotion-cache.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_cache@11.14.0/node_modules/@emotion/cache/dist/emotion-cache.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_hash@0.9.2/node_modules/@emotion/hash/dist/emotion-hash.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_hash@0.9.2/node_modules/@emotion/hash/dist/emotion-hash.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_is-prop-valid@1.3.1/node_modules/@emotion/is-prop-valid/dist/emotion-is-prop-valid.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_is-prop-valid@1.3.1/node_modules/@emotion/is-prop-valid/dist/emotion-is-prop-valid.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_memoize@0.9.0/node_modules/@emotion/memoize/dist/emotion-memoize.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_memoize@0.9.0/node_modules/@emotion/memoize/dist/emotion-memoize.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1/node_modules/@emotion/react/dist/emotion-element-d59e098f.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1/node_modules/@emotion/react/dist/emotion-element-d59e098f.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1/node_modules/@emotion/react/dist/emotion-react.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1/node_modules/@emotion/react/dist/emotion-react.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_serialize@1.3.3/node_modules/@emotion/serialize/dist/emotion-serialize.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_serialize@1.3.3/node_modules/@emotion/serialize/dist/emotion-serialize.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_sheet@1.4.0/node_modules/@emotion/sheet/dist/emotion-sheet.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_sheet@1.4.0/node_modules/@emotion/sheet/dist/emotion-sheet.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_styled@11.14.0_@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1__@types_react@18.3.23_react@18.3.1/node_modules/@emotion/styled/base/dist/emotion-styled-base.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_styled@11.14.0_@emotion_react@11.14.0_@types_react@18.3.23_react@18.3.1__@types_react@18.3.23_react@18.3.1/node_modules/@emotion/styled/base/dist/emotion-styled-base.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_unitless@0.10.0/node_modules/@emotion/unitless/dist/emotion-unitless.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_unitless@0.10.0/node_modules/@emotion/unitless/dist/emotion-unitless.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_use-insertion-effect-with-fallbacks@1.2.0_react@18.3.1/node_modules/@emotion/use-insertion-effect-with-fallbacks/dist/emotion-use-insertion-effect-with-fallbacks.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_use-insertion-effect-with-fallbacks@1.2.0_react@18.3.1/node_modules/@emotion/use-insertion-effect-with-fallbacks/dist/emotion-use-insertion-effect-with-fallbacks.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_utils@1.4.2/node_modules/@emotion/utils/dist/emotion-utils.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_utils@1.4.2/node_modules/@emotion/utils/dist/emotion-utils.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_weak-memoize@0.4.0/node_modules/@emotion/weak-memoize/dist/emotion-weak-memoize.esm.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@emotion_weak-memoize@0.4.0/node_modules/@emotion/weak-memoize/dist/emotion-weak-memoize.esm.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@tannin_compile@1.1.0/node_modules/@tannin/compile/index.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@tannin_compile@1.1.0/node_modules/@tannin/compile/index.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@tannin_evaluate@1.2.0/node_modules/@tannin/evaluate/index.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@tannin_evaluate@1.2.0/node_modules/@tannin/evaluate/index.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@tannin_plural-forms@1.1.0/node_modules/@tannin/plural-forms/index.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@tannin_plural-forms@1.1.0/node_modules/@tannin/plural-forms/index.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@tannin_postfix@1.1.0/node_modules/@tannin/postfix/index.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@tannin_postfix@1.1.0/node_modules/@tannin/postfix/index.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/progress-bar/index.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/progress-bar/index.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/progress-bar/styles.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/progress-bar/styles.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/colors-values.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/colors-values.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/config-values.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/config-values.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/space.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_components@29.12.0_@types_react@18.3.23_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@wordpress/components/build-module/utils/space.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createAddHook.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createAddHook.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createCurrentHook.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createCurrentHook.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createDidHook.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createDidHook.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createDoingHook.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createDoingHook.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createHasHook.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createHasHook.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createHooks.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createHooks.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createRemoveHook.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createRemoveHook.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createRunHook.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/createRunHook.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/index.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/index.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/validateHookName.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/validateHookName.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/validateNamespace.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_hooks@4.26.0/node_modules/@wordpress/hooks/build-module/validateNamespace.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_i18n@5.26.0/node_modules/@wordpress/i18n/build-module/create-i18n.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_i18n@5.26.0/node_modules/@wordpress/i18n/build-module/create-i18n.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_i18n@5.26.0/node_modules/@wordpress/i18n/build-module/default-i18n.js +2 -0
- package/dist/mjs/node_modules/.pnpm/@wordpress_i18n@5.26.0/node_modules/@wordpress/i18n/build-module/default-i18n.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/hoist-non-react-statics@3.3.2/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js +2 -0
- package/dist/mjs/node_modules/.pnpm/hoist-non-react-statics@3.3.2/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/cjs/react-is.development.js +10 -0
- package/dist/mjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/cjs/react-is.development.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/cjs/react-is.production.min.js +10 -0
- package/dist/mjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/cjs/react-is.production.min.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/index.js +2 -0
- package/dist/mjs/node_modules/.pnpm/react-is@16.13.1/node_modules/react-is/index.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/sprintf-js@1.1.3/node_modules/sprintf-js/src/sprintf.js +2 -0
- package/dist/mjs/node_modules/.pnpm/sprintf-js@1.1.3/node_modules/sprintf-js/src/sprintf.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Enum.js +2 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Enum.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Middleware.js +2 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Middleware.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Parser.js +2 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Parser.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Serializer.js +2 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Serializer.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Tokenizer.js +2 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Tokenizer.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Utility.js +2 -0
- package/dist/mjs/node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Utility.js.map +1 -0
- package/dist/mjs/node_modules/.pnpm/tannin@1.2.0/node_modules/tannin/index.js +2 -0
- package/dist/mjs/node_modules/.pnpm/tannin@1.2.0/node_modules/tannin/index.js.map +1 -0
- package/dist/mjs/providers/chart-context/chart-context.js +2 -0
- package/dist/mjs/providers/chart-context/chart-context.js.map +1 -0
- package/dist/mjs/providers/chart-context/utils.js +2 -0
- package/dist/mjs/providers/chart-context/utils.js.map +1 -0
- package/dist/mjs/providers/theme/theme-provider.js +1 -1
- package/dist/mjs/providers/theme/theme-provider.js.map +1 -1
- package/dist/mjs/style.css +1 -1
- package/package.json +11 -9
- package/src/components/bar-chart/bar-chart.tsx +115 -22
- package/src/components/grid-control/grid-control.module.scss +6 -6
- package/src/components/leaderboard-chart/README.md +199 -0
- package/src/components/leaderboard-chart/index.tsx +4 -0
- package/src/components/leaderboard-chart/leaderboard-chart.module.scss +93 -0
- package/src/components/leaderboard-chart/leaderboard-chart.tsx +214 -0
- package/src/components/line-chart/line-chart-annotation-label-popover.tsx +110 -0
- package/src/components/line-chart/line-chart-annotation.tsx +123 -22
- package/src/components/line-chart/line-chart-annotations-overlay.tsx +135 -0
- package/src/components/line-chart/line-chart-context.tsx +28 -0
- package/src/components/line-chart/line-chart.module.scss +69 -1
- package/src/components/line-chart/line-chart.tsx +357 -361
- package/src/components/pie-chart/pie-chart.tsx +29 -8
- package/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx +44 -21
- package/src/components/shared/format-metric-value.ts +92 -0
- package/src/components/shared/utils.ts +7 -0
- package/src/components/tooltip/accessible-tooltip.tsx +245 -0
- package/src/components/tooltip/base-tooltip.module.scss +9 -9
- package/src/index.ts +11 -0
- package/src/providers/chart-context/chart-context.test.tsx +230 -0
- package/src/providers/chart-context/chart-context.tsx +45 -0
- package/src/providers/chart-context/index.ts +3 -0
- package/src/providers/chart-context/types.ts +16 -0
- package/src/providers/chart-context/utils.ts +48 -0
- package/src/types.ts +29 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { ProgressBar } from '@wordpress/components';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { type FC } from 'react';
|
|
4
|
+
import { formatMetricValue } from '../shared/format-metric-value';
|
|
5
|
+
import styles from './leaderboard-chart.module.scss';
|
|
6
|
+
export interface LeaderboardEntry {
|
|
7
|
+
/**
|
|
8
|
+
* Unique internal key (e.g., 'key-direct')
|
|
9
|
+
*/
|
|
10
|
+
id: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Human-readable name (e.g., 'Direct')
|
|
14
|
+
*/
|
|
15
|
+
label: string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Value of the entry
|
|
19
|
+
*/
|
|
20
|
+
currentValue: number;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Value of the entry in the previous period
|
|
24
|
+
*/
|
|
25
|
+
previousValue: number;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Width of current bar, as % of the current value
|
|
29
|
+
*/
|
|
30
|
+
currentShare: number;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Width of previous bar, as % of the current value
|
|
34
|
+
*/
|
|
35
|
+
previousShare: number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Delta of the entry
|
|
39
|
+
*/
|
|
40
|
+
delta: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface LeaderboardChartProps {
|
|
44
|
+
/**
|
|
45
|
+
* Array of leaderboard entries to display
|
|
46
|
+
*/
|
|
47
|
+
data: LeaderboardEntry[];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Whether to show comparison data
|
|
51
|
+
*/
|
|
52
|
+
withComparison?: boolean;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Primary color for current period bars
|
|
56
|
+
*/
|
|
57
|
+
primaryColor?: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Secondary color for comparison period bars
|
|
61
|
+
*/
|
|
62
|
+
secondaryColor?: string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Formatter for values
|
|
66
|
+
*/
|
|
67
|
+
valueFormatter?: ( value: number ) => string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Formatter for delta values
|
|
71
|
+
*/
|
|
72
|
+
deltaFormatter?: ( value: number ) => string;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Whether the chart is in loading state
|
|
76
|
+
*/
|
|
77
|
+
loading?: boolean;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Additional CSS class name for the chart container
|
|
81
|
+
*/
|
|
82
|
+
className?: string;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Custom styling for the chart container
|
|
86
|
+
*/
|
|
87
|
+
style?: React.CSSProperties;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Default value formatter using formatMetricValue
|
|
92
|
+
*
|
|
93
|
+
* @param value - The numeric value to format
|
|
94
|
+
* @return Formatted string representation of the value
|
|
95
|
+
*/
|
|
96
|
+
const defaultValueFormatter = ( value: number ): string => {
|
|
97
|
+
return formatMetricValue( value, 'number', {
|
|
98
|
+
useMultipliers: true,
|
|
99
|
+
decimals: 1,
|
|
100
|
+
} );
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Default delta formatter using formatMetricValue
|
|
105
|
+
*
|
|
106
|
+
* @param value - The delta value to format
|
|
107
|
+
* @return Formatted percentage string
|
|
108
|
+
*/
|
|
109
|
+
const defaultDeltaFormatter = ( value: number ): string => {
|
|
110
|
+
return formatMetricValue( value / 100, 'average', {
|
|
111
|
+
decimals: 0,
|
|
112
|
+
signDisplay: 'exceptZero',
|
|
113
|
+
} );
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* LeaderboardChart component displays a ranked list of data with progress bars
|
|
118
|
+
* and optional comparison values.
|
|
119
|
+
*
|
|
120
|
+
* @param props - Component props
|
|
121
|
+
* @param props.data - Array of leaderboard entries to display
|
|
122
|
+
* @param props.withComparison - Whether to show comparison data
|
|
123
|
+
* @param props.primaryColor - Primary color for current period bars
|
|
124
|
+
* @param props.secondaryColor - Secondary color for comparison period bars
|
|
125
|
+
* @param props.valueFormatter - Custom formatter for values
|
|
126
|
+
* @param props.deltaFormatter - Custom formatter for delta values
|
|
127
|
+
* @param props.loading - Whether the chart is in loading state
|
|
128
|
+
* @param props.className - Additional CSS class name
|
|
129
|
+
* @param props.style - Custom styling for the chart container
|
|
130
|
+
* @return JSX element representing the leaderboard chart
|
|
131
|
+
*/
|
|
132
|
+
export const LeaderboardChart: FC< LeaderboardChartProps > = ( {
|
|
133
|
+
data,
|
|
134
|
+
withComparison = false,
|
|
135
|
+
primaryColor = '#3858E9',
|
|
136
|
+
secondaryColor = '#66BDFF',
|
|
137
|
+
valueFormatter = defaultValueFormatter,
|
|
138
|
+
deltaFormatter = defaultDeltaFormatter,
|
|
139
|
+
loading = false,
|
|
140
|
+
className,
|
|
141
|
+
style,
|
|
142
|
+
} ) => {
|
|
143
|
+
// TODO: Integrate with ThemeProvider:
|
|
144
|
+
// 1. Use theme.colors for primaryColor/secondaryColor defaults
|
|
145
|
+
// 2. Get delta sign colors from theme instead of hardcoding
|
|
146
|
+
// 3. Add useChartTheme() hook like other chart components
|
|
147
|
+
const signColors = [ '#D63638', '#757575', '#008A20' ];
|
|
148
|
+
|
|
149
|
+
const chartStyle = {
|
|
150
|
+
'--primary-color': primaryColor,
|
|
151
|
+
'--secondary-color': secondaryColor,
|
|
152
|
+
...style,
|
|
153
|
+
} as React.CSSProperties;
|
|
154
|
+
|
|
155
|
+
// Handle empty or undefined data
|
|
156
|
+
if ( ! data || data.length === 0 ) {
|
|
157
|
+
return (
|
|
158
|
+
<div
|
|
159
|
+
className={ clsx( styles.leaderboardChart, loading && styles.loading, className ) }
|
|
160
|
+
style={ chartStyle }
|
|
161
|
+
>
|
|
162
|
+
<div className={ styles.emptyState }>{ loading ? 'Loading...' : 'No data available' }</div>
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<div
|
|
169
|
+
className={ clsx( styles.leaderboardChart, loading && styles.loading, className ) }
|
|
170
|
+
style={ chartStyle }
|
|
171
|
+
>
|
|
172
|
+
{ data.map( entry => {
|
|
173
|
+
const colorIndex = Math.sign( entry.delta ) + 1;
|
|
174
|
+
const deltaColor = signColors[ colorIndex ];
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<div key={ entry.id } className={ styles.entryContainer }>
|
|
178
|
+
<div className={ styles.labelContainer }>
|
|
179
|
+
<span className={ styles.entryLabel }>{ entry.label }</span>
|
|
180
|
+
|
|
181
|
+
<div className={ styles.progressContainer }>
|
|
182
|
+
<ProgressBar
|
|
183
|
+
value={ entry.currentShare }
|
|
184
|
+
className={ clsx( styles.progressBar, styles.primaryBar ) }
|
|
185
|
+
/>
|
|
186
|
+
|
|
187
|
+
{ withComparison && (
|
|
188
|
+
<ProgressBar
|
|
189
|
+
value={ entry.previousShare }
|
|
190
|
+
className={ clsx( styles.progressBar, styles.secondaryBar ) }
|
|
191
|
+
/>
|
|
192
|
+
) }
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div className={ styles.valueContainer }>
|
|
197
|
+
<span className={ styles.currentValue }>
|
|
198
|
+
{ valueFormatter( entry.currentValue ) }
|
|
199
|
+
</span>
|
|
200
|
+
|
|
201
|
+
{ withComparison && (
|
|
202
|
+
<span className={ styles.deltaValue } style={ { color: deltaColor } }>
|
|
203
|
+
{ deltaFormatter( entry.delta ) }
|
|
204
|
+
</span>
|
|
205
|
+
) }
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
} ) }
|
|
210
|
+
</div>
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
export default LeaderboardChart;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Gridicon } from '@automattic/jetpack-components';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { useEffect, useId, useRef, useState } from 'react';
|
|
4
|
+
import { isSafari } from '../shared/utils';
|
|
5
|
+
import styles from './line-chart.module.scss';
|
|
6
|
+
import type { ButtonWithPopover, PopoverElement, ToggleEvent } from '../../types';
|
|
7
|
+
import type { FC } from 'react';
|
|
8
|
+
|
|
9
|
+
export const POPOVER_BUTTON_SIZE = 44;
|
|
10
|
+
|
|
11
|
+
interface LineChartAnnotationLabelWithPopoverProps {
|
|
12
|
+
title: string;
|
|
13
|
+
subtitle?: string;
|
|
14
|
+
renderLabel: FC< { title: string; subtitle?: string } >;
|
|
15
|
+
renderLabelPopover: FC< { title: string; subtitle?: string } >;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const LineChartAnnotationLabelWithPopover: FC< LineChartAnnotationLabelWithPopoverProps > = ( {
|
|
19
|
+
title,
|
|
20
|
+
subtitle,
|
|
21
|
+
renderLabel,
|
|
22
|
+
renderLabelPopover,
|
|
23
|
+
} ) => {
|
|
24
|
+
const popoverId = useId();
|
|
25
|
+
const buttonRef = useRef< HTMLButtonElement >( null );
|
|
26
|
+
const popoverRef = useRef< HTMLDivElement >( null );
|
|
27
|
+
const [ isPositioned, setIsPositioned ] = useState( false );
|
|
28
|
+
const isBrowserSafari = isSafari();
|
|
29
|
+
|
|
30
|
+
useEffect( () => {
|
|
31
|
+
const button = buttonRef.current;
|
|
32
|
+
const popover = popoverRef.current;
|
|
33
|
+
|
|
34
|
+
if ( ! button || ! popover ) return;
|
|
35
|
+
|
|
36
|
+
const positionPopover = () => {
|
|
37
|
+
// Popover positioning in Safari is complicated due to issues with SVG foreign objects (https://bugs.webkit.org/show_bug.cgi?id=23113), so let it be positioned in the centre of the viewport.
|
|
38
|
+
if ( ! isBrowserSafari ) {
|
|
39
|
+
const buttonRect = button.getBoundingClientRect();
|
|
40
|
+
popover.style.left = `${ buttonRect.right }px`;
|
|
41
|
+
popover.style.top = `${ buttonRect.top }px`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setIsPositioned( true );
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Position when popover shows
|
|
48
|
+
popover.addEventListener( 'toggle', ( e: ToggleEvent ) => {
|
|
49
|
+
if ( e.newState === 'open' ) {
|
|
50
|
+
positionPopover();
|
|
51
|
+
}
|
|
52
|
+
} );
|
|
53
|
+
|
|
54
|
+
// Initial positioning if already open
|
|
55
|
+
try {
|
|
56
|
+
if ( popover.matches( ':popover-open' ) ) {
|
|
57
|
+
positionPopover();
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// Ignore errors in test environments (e.g., JSDOM does not support :popover-open)
|
|
61
|
+
}
|
|
62
|
+
}, [ isBrowserSafari ] );
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className={ styles[ 'line-chart__annotation-label' ] }>
|
|
66
|
+
<button
|
|
67
|
+
ref={ buttonRef }
|
|
68
|
+
{ ...( { popovertarget: popoverId } as ButtonWithPopover ) }
|
|
69
|
+
className={ styles[ 'line-chart__annotation-label-trigger-button' ] }
|
|
70
|
+
style={ {
|
|
71
|
+
width: `${ POPOVER_BUTTON_SIZE }px`,
|
|
72
|
+
height: `${ POPOVER_BUTTON_SIZE }px`,
|
|
73
|
+
transform: `translate(${ POPOVER_BUTTON_SIZE / 2 }px, 0)`,
|
|
74
|
+
} }
|
|
75
|
+
aria-label={ title || 'View details' }
|
|
76
|
+
>
|
|
77
|
+
{ renderLabel( { title, subtitle } ) }
|
|
78
|
+
</button>
|
|
79
|
+
<div
|
|
80
|
+
ref={ popoverRef }
|
|
81
|
+
id={ popoverId }
|
|
82
|
+
{ ...( { popover: 'auto' } as PopoverElement ) }
|
|
83
|
+
className={ clsx(
|
|
84
|
+
styles[ 'line-chart__annotation-label-popover' ],
|
|
85
|
+
isPositioned && styles[ 'line-chart__annotation-label-popover--visible' ],
|
|
86
|
+
isBrowserSafari && styles[ 'line-chart__annotation-label-popover--safari' ]
|
|
87
|
+
) }
|
|
88
|
+
data-testid="line-chart-annotation-label-popover"
|
|
89
|
+
>
|
|
90
|
+
<div className={ styles[ 'line-chart__annotation-label-popover-header' ] }>
|
|
91
|
+
<div className={ styles[ 'line-chart__annotation-label-popover-content' ] }>
|
|
92
|
+
{ renderLabelPopover( { title, subtitle } ) }
|
|
93
|
+
</div>
|
|
94
|
+
<button
|
|
95
|
+
{ ...( {
|
|
96
|
+
popovertarget: popoverId,
|
|
97
|
+
popovertargetaction: 'hide',
|
|
98
|
+
} as ButtonWithPopover ) }
|
|
99
|
+
className={ styles[ 'line-chart__annotation-label-popover-close-button' ] }
|
|
100
|
+
aria-label="Close"
|
|
101
|
+
>
|
|
102
|
+
<Gridicon icon="cross" size={ 16 } />
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export default LineChartAnnotationLabelWithPopover;
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Annotation,
|
|
3
|
+
CircleSubject,
|
|
4
|
+
Connector,
|
|
5
|
+
HtmlLabel,
|
|
6
|
+
Label,
|
|
7
|
+
LineSubject,
|
|
8
|
+
} from '@visx/annotation';
|
|
2
9
|
import { DataContext } from '@visx/xychart';
|
|
3
|
-
import
|
|
10
|
+
import merge from 'deepmerge';
|
|
4
11
|
import { useContext, useRef, useEffect, useState, useMemo } from 'react';
|
|
5
12
|
import { useChartTheme } from '../../providers/theme/theme-provider';
|
|
13
|
+
import { isSafari } from '../shared/utils';
|
|
14
|
+
import LineChartAnnotationLabelWithPopover, {
|
|
15
|
+
POPOVER_BUTTON_SIZE,
|
|
16
|
+
} from './line-chart-annotation-label-popover';
|
|
6
17
|
import type { DataPointDate } from '../../types';
|
|
7
18
|
import type { CircleSubjectProps } from '@visx/annotation/lib/components/CircleSubject';
|
|
8
19
|
import type { ConnectorProps } from '@visx/annotation/lib/components/Connector';
|
|
@@ -15,7 +26,10 @@ export type AnnotationStyles = {
|
|
|
15
26
|
circleSubject?: Omit< CircleSubjectProps, 'x' | 'y' > & { fill?: string };
|
|
16
27
|
lineSubject?: Omit< LineSubjectProps, 'x' | 'y' >;
|
|
17
28
|
connector?: Omit< ConnectorProps, 'x' | 'y' | 'dx' | 'dy' >;
|
|
18
|
-
label?: Omit< LabelProps, 'title' | 'subtitle'
|
|
29
|
+
label?: Omit< LabelProps, 'title' | 'subtitle' | 'x' | 'y' > & {
|
|
30
|
+
x?: number | 'start' | 'end';
|
|
31
|
+
y?: number | 'start' | 'end';
|
|
32
|
+
};
|
|
19
33
|
};
|
|
20
34
|
|
|
21
35
|
type SubjectType = 'circle' | 'line-vertical' | 'line-horizontal';
|
|
@@ -30,6 +44,8 @@ export type LineChartAnnotationProps = {
|
|
|
30
44
|
subjectType?: SubjectType;
|
|
31
45
|
styles?: AnnotationStyles;
|
|
32
46
|
testId?: string;
|
|
47
|
+
renderLabel?: FC< { title: string; subtitle?: string } >;
|
|
48
|
+
renderLabelPopover?: FC< { title: string; subtitle?: string } >;
|
|
33
49
|
};
|
|
34
50
|
|
|
35
51
|
export const getLabelPosition = ( {
|
|
@@ -79,6 +95,7 @@ export const getLabelPosition = ( {
|
|
|
79
95
|
|
|
80
96
|
if ( effectiveX + annotationMaxWidth > xMax ) {
|
|
81
97
|
isFlippedHorizontally = true;
|
|
98
|
+
|
|
82
99
|
if ( subjectType === 'circle' ) {
|
|
83
100
|
dx = -dx; // Just flip to the left side with same offset
|
|
84
101
|
} else if ( subjectType === 'line-vertical' ) {
|
|
@@ -142,7 +159,7 @@ const getVerticalAnchor = (
|
|
|
142
159
|
return y - height < yMax ? 'start' : 'end';
|
|
143
160
|
}
|
|
144
161
|
|
|
145
|
-
return '
|
|
162
|
+
return 'start';
|
|
146
163
|
}
|
|
147
164
|
|
|
148
165
|
return undefined;
|
|
@@ -155,6 +172,8 @@ const LineChartAnnotation: FC< LineChartAnnotationProps > = ( {
|
|
|
155
172
|
subjectType = 'circle',
|
|
156
173
|
styles: datumStyles,
|
|
157
174
|
testId,
|
|
175
|
+
renderLabel,
|
|
176
|
+
renderLabelPopover,
|
|
158
177
|
} ) => {
|
|
159
178
|
const providerTheme = useChartTheme();
|
|
160
179
|
const { xScale, yScale } = useContext( DataContext ) || {};
|
|
@@ -162,11 +181,11 @@ const LineChartAnnotation: FC< LineChartAnnotationProps > = ( {
|
|
|
162
181
|
const [ height, setHeight ] = useState< number | null >( null );
|
|
163
182
|
|
|
164
183
|
// Deep merge styles to preserve nested object properties
|
|
165
|
-
const styles = merge(
|
|
184
|
+
const styles = merge( providerTheme.annotationStyles ?? {}, datumStyles ?? {} );
|
|
166
185
|
|
|
167
186
|
// Measure the label height once after initial render
|
|
168
187
|
useEffect( () => {
|
|
169
|
-
if ( labelRef.current ) {
|
|
188
|
+
if ( labelRef.current?.getBBox ) {
|
|
170
189
|
const bbox = labelRef.current.getBBox();
|
|
171
190
|
setHeight( bbox.height );
|
|
172
191
|
}
|
|
@@ -183,6 +202,22 @@ const LineChartAnnotation: FC< LineChartAnnotationProps > = ( {
|
|
|
183
202
|
const [ yMin, yMax ] = yScale.range().map( Number );
|
|
184
203
|
const [ xMin, xMax ] = xScale.range().map( Number );
|
|
185
204
|
|
|
205
|
+
// If a custom label is provided, use the provided position
|
|
206
|
+
if ( renderLabel ) {
|
|
207
|
+
return {
|
|
208
|
+
x,
|
|
209
|
+
dx: 0,
|
|
210
|
+
y,
|
|
211
|
+
dy: 0,
|
|
212
|
+
yMin,
|
|
213
|
+
yMax,
|
|
214
|
+
xMin,
|
|
215
|
+
xMax,
|
|
216
|
+
isFlippedHorizontally: false,
|
|
217
|
+
isFlippedVertically: false,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
186
221
|
const position = getLabelPosition( {
|
|
187
222
|
subjectType,
|
|
188
223
|
x,
|
|
@@ -195,13 +230,61 @@ const LineChartAnnotation: FC< LineChartAnnotationProps > = ( {
|
|
|
195
230
|
} );
|
|
196
231
|
|
|
197
232
|
return { x, y, yMin, yMax, xMin, xMax, ...position };
|
|
198
|
-
}, [ datum, xScale, yScale, subjectType, styles?.label?.maxWidth, height ] );
|
|
233
|
+
}, [ datum, xScale, yScale, subjectType, styles?.label?.maxWidth, height, renderLabel ] );
|
|
199
234
|
|
|
200
235
|
if ( ! positionData ) return null;
|
|
201
236
|
|
|
202
237
|
const { x, y, yMin, yMax, xMin, xMax, dx, dy, isFlippedHorizontally, isFlippedVertically } =
|
|
203
238
|
positionData;
|
|
204
239
|
|
|
240
|
+
const getLabelY = () => {
|
|
241
|
+
const labelY = styles?.label?.y;
|
|
242
|
+
|
|
243
|
+
if ( labelY === 'start' ) return yMax;
|
|
244
|
+
if ( labelY === 'end' ) return yMin;
|
|
245
|
+
|
|
246
|
+
return labelY;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const getLabelX = () => {
|
|
250
|
+
const labelX = styles?.label?.x;
|
|
251
|
+
|
|
252
|
+
if ( labelX === 'start' ) return xMin;
|
|
253
|
+
if ( labelX === 'end' ) return xMax;
|
|
254
|
+
|
|
255
|
+
return labelX;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const labelPosition = {
|
|
259
|
+
x: getLabelX(),
|
|
260
|
+
y: getLabelY(),
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// Safari has a bug where children of an SVG foreignObject are not positioned correctly https://bugs.webkit.org/show_bug.cgi?id=23113
|
|
264
|
+
// This is a workaround to position the label correctly
|
|
265
|
+
const getSafariHTMLLabelPosition = () => {
|
|
266
|
+
const labelWidth = POPOVER_BUTTON_SIZE;
|
|
267
|
+
const labelHeight = POPOVER_BUTTON_SIZE;
|
|
268
|
+
|
|
269
|
+
return isSafari()
|
|
270
|
+
? {
|
|
271
|
+
transform: `translate(${
|
|
272
|
+
x +
|
|
273
|
+
( dx || 0 ) +
|
|
274
|
+
( typeof labelPosition.x === 'number' ? labelPosition.x - x : 0 ) -
|
|
275
|
+
labelWidth
|
|
276
|
+
}px, ${
|
|
277
|
+
y +
|
|
278
|
+
( dy || 0 ) +
|
|
279
|
+
( typeof labelPosition.y === 'number' ? labelPosition.y - y : 0 ) -
|
|
280
|
+
labelHeight
|
|
281
|
+
}px)`,
|
|
282
|
+
width: labelWidth,
|
|
283
|
+
height: labelHeight,
|
|
284
|
+
}
|
|
285
|
+
: undefined;
|
|
286
|
+
};
|
|
287
|
+
|
|
205
288
|
return (
|
|
206
289
|
<g data-testid={ testId }>
|
|
207
290
|
<Annotation x={ x } y={ y } dx={ dx } dy={ dy }>
|
|
@@ -221,21 +304,39 @@ const LineChartAnnotation: FC< LineChartAnnotationProps > = ( {
|
|
|
221
304
|
{ ...{ ...styles?.lineSubject, orientation: 'horizontal' } }
|
|
222
305
|
/>
|
|
223
306
|
) }
|
|
224
|
-
|
|
225
|
-
<
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
307
|
+
{ renderLabel ? (
|
|
308
|
+
<HtmlLabel { ...styles?.label } { ...labelPosition }>
|
|
309
|
+
<div style={ getSafariHTMLLabelPosition() }>
|
|
310
|
+
{ renderLabelPopover ? (
|
|
311
|
+
<LineChartAnnotationLabelWithPopover
|
|
312
|
+
title={ title }
|
|
313
|
+
subtitle={ subtitle }
|
|
314
|
+
renderLabel={ renderLabel }
|
|
315
|
+
renderLabelPopover={ renderLabelPopover }
|
|
316
|
+
/>
|
|
317
|
+
) : (
|
|
318
|
+
renderLabel( { title, subtitle } )
|
|
319
|
+
) }
|
|
320
|
+
</div>
|
|
321
|
+
</HtmlLabel>
|
|
322
|
+
) : (
|
|
323
|
+
<g ref={ labelRef }>
|
|
324
|
+
<Label
|
|
325
|
+
title={ title }
|
|
326
|
+
subtitle={ subtitle }
|
|
327
|
+
{ ...styles?.label }
|
|
328
|
+
{ ...labelPosition }
|
|
329
|
+
horizontalAnchor={ getHorizontalAnchor( subjectType, isFlippedHorizontally ) }
|
|
330
|
+
verticalAnchor={ getVerticalAnchor(
|
|
331
|
+
subjectType,
|
|
332
|
+
isFlippedVertically,
|
|
333
|
+
y,
|
|
334
|
+
yMax,
|
|
335
|
+
height ?? ANNOTATION_INIT_HEIGHT
|
|
336
|
+
) }
|
|
337
|
+
/>
|
|
338
|
+
</g>
|
|
339
|
+
) }
|
|
239
340
|
</Annotation>
|
|
240
341
|
</g>
|
|
241
342
|
);
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { DataContext } from '@visx/xychart';
|
|
2
|
+
import { useEffect, useState, useCallback } from 'react';
|
|
3
|
+
import { useLineChartContext } from './line-chart-context';
|
|
4
|
+
import styles from './line-chart.module.scss';
|
|
5
|
+
import type { AxisScale } from '@visx/axis';
|
|
6
|
+
import type { FC, ReactNode } from 'react';
|
|
7
|
+
|
|
8
|
+
export interface LineChartAnnotationsProps {
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface ScaleData {
|
|
13
|
+
xScale: AxisScale< Date >;
|
|
14
|
+
yScale: AxisScale< number >;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const LineChartAnnotationsOverlay: FC< LineChartAnnotationsProps > = ( { children } ) => {
|
|
18
|
+
const { chartRef, chartWidth, chartHeight } = useLineChartContext();
|
|
19
|
+
|
|
20
|
+
const [ scales, setScales ] = useState< ScaleData | null >( null );
|
|
21
|
+
const [ scalesStable, setScalesStable ] = useState< boolean >( false );
|
|
22
|
+
|
|
23
|
+
// Create a signature for scale data to enable easy comparison
|
|
24
|
+
const createScaleSignature = useCallback( ( scaleData: ScaleData ) => {
|
|
25
|
+
const xDomain = scaleData.xScale.domain();
|
|
26
|
+
const yDomain = scaleData.yScale.domain();
|
|
27
|
+
const xRange = scaleData.xScale.range();
|
|
28
|
+
const yRange = scaleData.yScale.range();
|
|
29
|
+
|
|
30
|
+
return `${ xDomain.join( ',' ) }-${ yDomain.join( ',' ) }-${ xRange.join(
|
|
31
|
+
','
|
|
32
|
+
) }-${ yRange.join( ',' ) }`;
|
|
33
|
+
}, [] );
|
|
34
|
+
|
|
35
|
+
// Get scales from chart ref and return them with signature for comparison
|
|
36
|
+
const getScalesData = useCallback( () => {
|
|
37
|
+
if ( chartRef?.current ) {
|
|
38
|
+
const scaleData = chartRef.current.getScales();
|
|
39
|
+
|
|
40
|
+
if ( scaleData ) {
|
|
41
|
+
const scaleInfo = {
|
|
42
|
+
xScale: scaleData.xScale as AxisScale< Date >,
|
|
43
|
+
yScale: scaleData.yScale as AxisScale< number >,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
scales: scaleInfo,
|
|
48
|
+
signature: createScaleSignature( scaleInfo ),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
|
+
}, [ chartRef, createScaleSignature ] );
|
|
55
|
+
|
|
56
|
+
// The chart resizes on render so we need to monitor the scales until they stabilize
|
|
57
|
+
useEffect( () => {
|
|
58
|
+
let timeoutId: number | null = null;
|
|
59
|
+
let lastSignature: string | null = null;
|
|
60
|
+
let retryCount = 0;
|
|
61
|
+
const maxRetries = 20; // 20 * 50ms = 1 second max
|
|
62
|
+
const checkInterval = 50; // Check every 50ms
|
|
63
|
+
|
|
64
|
+
// Reset stability state when monitoring starts
|
|
65
|
+
setScalesStable( false );
|
|
66
|
+
|
|
67
|
+
const monitorScales = () => {
|
|
68
|
+
const currentScaleData = getScalesData();
|
|
69
|
+
|
|
70
|
+
// If we got scales, compare signatures
|
|
71
|
+
if ( currentScaleData ) {
|
|
72
|
+
// Check if scales have settled by comparing signatures
|
|
73
|
+
const scalesSettled = lastSignature && currentScaleData.signature === lastSignature;
|
|
74
|
+
|
|
75
|
+
if ( scalesSettled ) {
|
|
76
|
+
// Scales have stabilized, mark as stable
|
|
77
|
+
setScalesStable( true );
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Update scales and remember signature for next comparison
|
|
82
|
+
setScales( currentScaleData.scales );
|
|
83
|
+
lastSignature = currentScaleData.signature;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Continue monitoring if we haven't exceeded max retries
|
|
87
|
+
if ( retryCount < maxRetries ) {
|
|
88
|
+
retryCount++;
|
|
89
|
+
timeoutId = setTimeout( monitorScales, checkInterval ) as unknown as number;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
monitorScales();
|
|
94
|
+
|
|
95
|
+
return () => {
|
|
96
|
+
if ( timeoutId ) {
|
|
97
|
+
clearTimeout( timeoutId );
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}, [ getScalesData, chartWidth, chartHeight ] );
|
|
101
|
+
|
|
102
|
+
// Early return if no chart data available
|
|
103
|
+
if ( ! chartRef || ! children ) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if ( ! scales || ! scalesStable ) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Create a DataContext value that mimics what visx provides
|
|
112
|
+
// We're intentionally providing minimal context for annotations to work
|
|
113
|
+
const dataContextValue = {
|
|
114
|
+
xScale: scales.xScale,
|
|
115
|
+
yScale: scales.yScale,
|
|
116
|
+
margin: { top: 0, right: 0, bottom: 0, left: 0 },
|
|
117
|
+
width: chartWidth,
|
|
118
|
+
height: chartHeight,
|
|
119
|
+
} as unknown as Parameters< typeof DataContext.Provider >[ 0 ][ 'value' ];
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<DataContext.Provider value={ dataContextValue }>
|
|
123
|
+
<svg
|
|
124
|
+
width={ chartWidth }
|
|
125
|
+
height={ chartHeight }
|
|
126
|
+
className={ styles[ 'line-chart__annotations-overlay' ] }
|
|
127
|
+
data-testid="line-chart-annotations-overlay"
|
|
128
|
+
>
|
|
129
|
+
{ children }
|
|
130
|
+
</svg>
|
|
131
|
+
</DataContext.Provider>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export default LineChartAnnotationsOverlay;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface LineChartRef {
|
|
4
|
+
getScales: () => { xScale: unknown; yScale: unknown } | null;
|
|
5
|
+
getChartDimensions: () => {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
margin: { top?: number; right?: number; bottom?: number; left?: number };
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Local context for LineChart implicit state sharing
|
|
13
|
+
export interface LineChartContextValue {
|
|
14
|
+
chartId: string;
|
|
15
|
+
chartRef: React.RefObject< LineChartRef >;
|
|
16
|
+
chartWidth: number;
|
|
17
|
+
chartHeight: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const LineChartContext = createContext< LineChartContextValue | null >( null );
|
|
21
|
+
|
|
22
|
+
export const useLineChartContext = (): LineChartContextValue => {
|
|
23
|
+
const context = useContext( LineChartContext );
|
|
24
|
+
if ( ! context ) {
|
|
25
|
+
throw new Error( 'useLineChartContext must be used within a LineChart component' );
|
|
26
|
+
}
|
|
27
|
+
return context;
|
|
28
|
+
};
|