From ebc9c4cecba4f0d27b80bf296647dba0f568ad9f Mon Sep 17 00:00:00 2001 From: Dan Labrecque Date: Fri, 26 Apr 2024 19:23:20 -0400 Subject: [PATCH] feat(charts): skeletons https://github.com/patternfly/patternfly-react/issues/10310 --- .../src/components/Chart/Chart.tsx | 13 +- .../src/components/ChartAxis/ChartAxis.tsx | 6 +- .../components/ChartBullet/ChartBullet.tsx | 48 +- .../ChartBulletComparativeMeasure.tsx | 1 + .../ChartBulletComparativeWarningMeasure.tsx | 1 + .../ChartBullet/ChartBulletGroupTitle.tsx | 3 +- .../ChartBullet/ChartBulletTitle.tsx | 3 +- .../ChartBullet/utils/chart-bullet-theme.ts | 5 + .../ChartCursorContainer.tsx | 3 +- .../src/components/ChartDonut/ChartDonut.tsx | 6 +- .../components/ChartLegend/ChartLegend.tsx | 6 +- .../src/components/ChartTheme/ChartTheme.ts | 12 +- .../components/ChartTheme/ChartThemeColor.ts | 4 +- .../components/ChartTheme/ChartThemeTypes.ts | 11 +- .../ChartTheme/themes/base-theme.ts | 2 +- .../themes/colors/skeleton-theme.ts | 27 + .../ChartTheme/themes/skeleton-theme.ts | 180 ++++ .../ChartUtils/chart-theme-types.ts | 106 ++- .../src/components/ChartUtils/chart-theme.ts | 18 +- .../ResizeObserver/examples/resizeObserver.md | 1 + .../Skeletons/examples/skeletons.md | 796 ++++++++++++++++++ 21 files changed, 1198 insertions(+), 54 deletions(-) create mode 100644 packages/react-charts/src/components/ChartTheme/themes/colors/skeleton-theme.ts create mode 100644 packages/react-charts/src/components/ChartTheme/themes/skeleton-theme.ts create mode 100644 packages/react-charts/src/components/Skeletons/examples/skeletons.md diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index 4c5882dbad1..ed96eb90efa 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -33,6 +33,7 @@ import { getChartTheme } from '../ChartUtils/chart-theme-types'; import { useEffect } from 'react'; import { ChartLabel } from '../ChartLabel/ChartLabel'; import { ChartPoint } from '../ChartPoint/ChartPoint'; +import { ChartThemeColor } from '../ChartTheme/ChartThemeColor'; /** * Chart is a wrapper component that reconciles the domain for all its children, controls the layout of the chart, @@ -473,7 +474,7 @@ export const Chart: React.FunctionComponent = ({ children, colorScale, hasPatterns, - legendAllowWrap = false, + legendAllowWrap, legendComponent = , legendData, legendPosition = ChartCommonStyles.legend.position, @@ -550,7 +551,11 @@ export const Chart: React.FunctionComponent = ({ labelComponent: legendComponent.props.labelComponent ? ( React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) ) : ( - + ) }), ...legendComponent.props @@ -642,7 +647,9 @@ export const Chart: React.FunctionComponent = ({ return ( : container // Omit cursor and tooltips + } height={height} name={name} padding={defaultPadding} diff --git a/packages/react-charts/src/components/ChartAxis/ChartAxis.tsx b/packages/react-charts/src/components/ChartAxis/ChartAxis.tsx index 3949ea2cb35..6f9954a76d7 100644 --- a/packages/react-charts/src/components/ChartAxis/ChartAxis.tsx +++ b/packages/react-charts/src/components/ChartAxis/ChartAxis.tsx @@ -462,7 +462,8 @@ export const ChartAxis: React.FunctionComponent = ({ ...(name && { id: () => `${name}-${(axisLabelComponent as any).type.displayName}` }), - ...axisLabelComponent.props + ...axisLabelComponent.props, + ...(theme.skeleton && theme.skeleton) // override backgroundStyle }); const getTickLabelComponent = () => @@ -470,7 +471,8 @@ export const ChartAxis: React.FunctionComponent = ({ ...(name && { id: (props: any) => `${name}-${(tickLabelComponent as any).type.displayName}-${props.index}` }), - ...tickLabelComponent.props + ...tickLabelComponent.props, + ...(theme.skeleton && theme.skeleton) // override backgroundStyle }); // Note: containerComponent is required for theme diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index 42ab60edcd5..b6dbace840c 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -594,6 +594,8 @@ export const ChartBullet: React.FunctionComponent = ({ standalone: false, subTitle: groupSubTitle, title: groupTitle, + theme, + themeColor, width, ...groupTitleComponent.props }); @@ -608,6 +610,7 @@ export const ChartBullet: React.FunctionComponent = ({ standalone: false, subTitle, theme, + themeColor, title, titlePosition, width, @@ -617,7 +620,12 @@ export const ChartBullet: React.FunctionComponent = ({ // Comparative error measure const comparativeErrorMeasure = React.cloneElement(comparativeErrorMeasureComponent, { allowTooltip, - barWidth: getComparativeMeasureErrorWidth({ height: chartSize.height, horizontal, width: chartSize.width }), + barWidth: getComparativeMeasureErrorWidth({ + height: chartSize.height, + horizontal, + themeColor, + width: chartSize.width + }), constrainToVisibleArea, data: comparativeErrorMeasureData, domain, @@ -627,6 +635,7 @@ export const ChartBullet: React.FunctionComponent = ({ labels, padding, standalone: false, + themeColor, width: chartSize.width, y: comparativeErrorMeasureDataY, ...comparativeErrorMeasureComponent.props @@ -635,7 +644,12 @@ export const ChartBullet: React.FunctionComponent = ({ // Comparative warning measure const comparativeWarningMeasure = React.cloneElement(comparativeWarningMeasureComponent, { allowTooltip, - barWidth: getComparativeMeasureWarningWidth({ height: chartSize.height, horizontal, width: chartSize.width }), + barWidth: getComparativeMeasureWarningWidth({ + height: chartSize.height, + horizontal, + themeColor, + width: chartSize.width + }), constrainToVisibleArea, data: comparativeWarningMeasureData, domain, @@ -645,6 +659,7 @@ export const ChartBullet: React.FunctionComponent = ({ labels, padding, standalone: false, + themeColor, width: chartSize.width, y: comparativeWarningMeasureDataY, ...comparativeWarningMeasureComponent.props @@ -652,13 +667,14 @@ export const ChartBullet: React.FunctionComponent = ({ // Comparative zero measure const comparativeZeroMeasure = React.cloneElement(comparativeZeroMeasureComponent, { - barWidth: getComparativeMeasureWidth({ height: chartSize.height, horizontal, width: chartSize.width }), + barWidth: getComparativeMeasureWidth({ height: chartSize.height, horizontal, themeColor, width: chartSize.width }), data: [{ y: 0 }], domain, height: chartSize.height, horizontal, padding, standalone: false, + themeColor, width: chartSize.width, ...comparativeZeroMeasureComponent.props }); @@ -691,6 +707,7 @@ export const ChartBullet: React.FunctionComponent = ({ orientation: legendOrientation, position: legendPosition, theme, + themeColor, ...(legendDirection === 'rtl' && { dataComponent: legendComponent.props.dataComponent ? ( React.cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) @@ -700,9 +717,17 @@ export const ChartBullet: React.FunctionComponent = ({ }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( - React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) + React.cloneElement(legendComponent.props.labelComponent, { + direction: 'rtl', + dx: legendXOffset - 30, + ...(theme.skeleton && theme.skeleton) // override backgroundStyle + }) ) : ( - + ) }), ...legendComponent.props @@ -720,7 +745,7 @@ export const ChartBullet: React.FunctionComponent = ({ labelComponent: allowTooltip ? : undefined, labels, padding, - size: getPrimaryDotMeasureSize({ height: chartSize.height, horizontal, width: chartSize.width }), + size: getPrimaryDotMeasureSize({ height: chartSize.height, horizontal, themeColor, width: chartSize.width }), standalone: false, themeColor, width: chartSize.width, @@ -732,7 +757,12 @@ export const ChartBullet: React.FunctionComponent = ({ const primarySegmentedMeasure = React.cloneElement(primarySegmentedMeasureComponent, { allowTooltip, constrainToVisibleArea, - barWidth: getPrimarySegmentedMeasureWidth({ height: chartSize.height, horizontal, width: chartSize.width }), + barWidth: getPrimarySegmentedMeasureWidth({ + height: chartSize.height, + horizontal, + themeColor, + width: chartSize.width + }), data: primarySegmentedMeasureData, domain, height: chartSize.height, @@ -752,7 +782,7 @@ export const ChartBullet: React.FunctionComponent = ({ const qualitativeRange = React.cloneElement(qualitativeRangeComponent, { allowTooltip, constrainToVisibleArea, - barWidth: getQualitativeRangeBarWidth({ height: chartSize.height, horizontal, width: chartSize.width }), + barWidth: getQualitativeRangeBarWidth({ height: chartSize.height, horizontal, themeColor, width: chartSize.width }), data: qualitativeRangeData, domain, height: chartSize.height, @@ -762,6 +792,7 @@ export const ChartBullet: React.FunctionComponent = ({ labels, padding, standalone: false, + themeColor, width: chartSize.width, y: qualitativeRangeDataY, y0: qualitativeRangeDataY0, @@ -868,6 +899,7 @@ export const ChartBullet: React.FunctionComponent = ({ offsetY: horizontal ? 80 - defaultPadding.top * 0.5 + (defaultPadding.bottom * 0.5 - 25) : 0, padding, standalone: false, + themeColor, tickCount: ChartBulletStyles.axisTickCount, tickValues: getTickValues((domain as any).y[0], (domain as any).y[1]), width: chartSize.width, diff --git a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.tsx b/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.tsx index 14f68302c9e..40b45a68f59 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBulletComparativeMeasure.tsx @@ -230,6 +230,7 @@ export const ChartBulletComparativeMeasure: React.FunctionComponent = dy, labelPosition }), - ...titleComponent.props + ...titleComponent.props, + ...(theme.skeleton && theme.skeleton) // override backgroundStyle }); }; diff --git a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-theme.ts b/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-theme.ts index 3550f57b8e2..2cfb13f9950 100644 --- a/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-theme.ts +++ b/packages/react-charts/src/components/ChartBullet/utils/chart-bullet-theme.ts @@ -7,6 +7,8 @@ import { } from './chart-bullet-data'; import { ChartThemeDefinition } from '../../ChartTheme/ChartTheme'; import { getBulletTheme } from '../../ChartUtils/chart-theme-types'; +import { ChartThemeColor } from '../../ChartTheme/ChartThemeColor'; +import { SkeletonColorTheme } from '../../ChartTheme/themes/colors/skeleton-theme'; interface ChartBulletThemeInterface { comparativeErrorMeasureData?: any[]; @@ -134,5 +136,8 @@ export const getBulletThemeWithLegendColorScale = ({ const theme = getBulletTheme(themeColor); theme.legend.colorScale = [...colorScale]; + if (themeColor === ChartThemeColor.skeleton) { + theme.legend.colorScale = SkeletonColorTheme.legend.colorScale; + } return theme; }; diff --git a/packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.tsx b/packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.tsx index a5790a3523c..0061d7ed474 100644 --- a/packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.tsx +++ b/packages/react-charts/src/components/ChartCursorContainer/ChartCursorContainer.tsx @@ -213,7 +213,8 @@ export const ChartCursorContainer: React.FunctionComponent = ({ padding: defaultPadding, width }), - ...subTitleProps + ...subTitleProps, + ...(theme.skeleton && theme.skeleton) // override backgroundStyle }); }; @@ -692,7 +693,8 @@ export const ChartDonut: React.FunctionComponent = ({ padding: defaultPadding, width }), - ...titleProps + ...titleProps, + ...(theme.skeleton && theme.skeleton) // override backgroundStyle }); }; diff --git a/packages/react-charts/src/components/ChartLegend/ChartLegend.tsx b/packages/react-charts/src/components/ChartLegend/ChartLegend.tsx index 1f4dae53015..2a1508f663a 100644 --- a/packages/react-charts/src/components/ChartLegend/ChartLegend.tsx +++ b/packages/react-charts/src/components/ChartLegend/ChartLegend.tsx @@ -350,14 +350,16 @@ export const ChartLegend: React.FunctionComponent = ({ const getLabelComponent = () => React.cloneElement(labelComponent, { ...(name && { id: (props: any) => `${name}-${(labelComponent as any).type.displayName}-${props.index}` }), - ...labelComponent.props + ...labelComponent.props, + ...(theme.skeleton && theme.skeleton) // override backgroundStyle }); const getTitleComponent = () => React.cloneElement(titleComponent, { // Victory doesn't appear to call the id function here, but it's valid for label components ...(name && { id: () => `${name}-${(titleComponent as any).type.displayName}` }), - ...titleComponent.props + ...titleComponent.props, + ...(theme.skeleton && theme.skeleton) // override backgroundStyle }); // Note: containerComponent is required for theme diff --git a/packages/react-charts/src/components/ChartTheme/ChartTheme.ts b/packages/react-charts/src/components/ChartTheme/ChartTheme.ts index fcd2b214015..1fcac65b4c1 100644 --- a/packages/react-charts/src/components/ChartTheme/ChartTheme.ts +++ b/packages/react-charts/src/components/ChartTheme/ChartTheme.ts @@ -1,7 +1,17 @@ import { VictoryThemeDefinition } from 'victory-core'; // Note: Victory incorrectly typed ThemeBaseProps.padding as number instead of PaddingProps -export interface ChartThemeDefinitionInterface extends VictoryThemeDefinition {} +export interface ChartThemeDefinitionInterface extends VictoryThemeDefinition { + skeleton?: { + backgroundStyle?: { + fill?: string; + }; + style?: { + fill?: string; + stroke?: string; + }; + }; +} /** * Chart theme definition diff --git a/packages/react-charts/src/components/ChartTheme/ChartThemeColor.ts b/packages/react-charts/src/components/ChartTheme/ChartThemeColor.ts index 176c4e067e3..e501941a174 100644 --- a/packages/react-charts/src/components/ChartTheme/ChartThemeColor.ts +++ b/packages/react-charts/src/components/ChartTheme/ChartThemeColor.ts @@ -10,6 +10,7 @@ interface ChartThemeColorInterface { multiUnordered: string; orange: string; purple: string; + skeleton: string; } /** @@ -49,5 +50,6 @@ export const ChartThemeColor: ChartThemeColorInterface = { multiOrdered: 'multi-ordered', multiUnordered: 'multi-unordered', orange: 'orange', - purple: 'purple' + purple: 'purple', + skeleton: 'skeleton' }; diff --git a/packages/react-charts/src/components/ChartTheme/ChartThemeTypes.ts b/packages/react-charts/src/components/ChartTheme/ChartThemeTypes.ts index e2cf585e630..18aaee562e2 100644 --- a/packages/react-charts/src/components/ChartTheme/ChartThemeTypes.ts +++ b/packages/react-charts/src/components/ChartTheme/ChartThemeTypes.ts @@ -1,6 +1,7 @@ import { ChartThemeDefinition } from './ChartTheme'; import { AxisTheme } from './themes/components/axis-theme'; import { BaseTheme } from './themes/base-theme'; +import { SkeletonTheme } from './themes/skeleton-theme'; import { BulletTheme, BulletComparativeErrorMeasureTheme, @@ -108,13 +109,19 @@ export const ChartDonutTheme: ChartThemeDefinition = DonutTheme; export const ChartDonutThresholdDynamicTheme: ChartThemeDefinition = DonutThresholdDynamicTheme; /** - * ChartDonutThresholdStatic theme + * Donut threshold static theme * @private */ export const ChartDonutThresholdStaticTheme: ChartThemeDefinition = DonutThresholdStaticTheme; /** - * Donut threshold static theme + * Skeleton theme + * @private + */ +export const ChartSkeletonTheme: ChartThemeDefinition = SkeletonTheme; + +/** + * Threshold static theme * @private */ export const ChartThresholdTheme: ChartThemeDefinition = ThresholdTheme; diff --git a/packages/react-charts/src/components/ChartTheme/themes/base-theme.ts b/packages/react-charts/src/components/ChartTheme/themes/base-theme.ts index dd5233d0188..efbb59f94c5 100644 --- a/packages/react-charts/src/components/ChartTheme/themes/base-theme.ts +++ b/packages/react-charts/src/components/ChartTheme/themes/base-theme.ts @@ -167,7 +167,7 @@ export const BaseTheme = { }, grid: { fill: chart_axis_grid_Fill.var, - stroke: 'none', + stroke: 'transparent', pointerEvents: chart_axis_grid_PointerEvents.value, strokeLinecap: STROKE_LINE_CAP, strokeLinejoin: STROKE_LINE_JOIN diff --git a/packages/react-charts/src/components/ChartTheme/themes/colors/skeleton-theme.ts b/packages/react-charts/src/components/ChartTheme/themes/colors/skeleton-theme.ts new file mode 100644 index 00000000000..ce5cab05642 --- /dev/null +++ b/packages/react-charts/src/components/ChartTheme/themes/colors/skeleton-theme.ts @@ -0,0 +1,27 @@ +/* eslint-disable camelcase */ +import { ColorTheme } from '../color-theme'; +import chart_bullet_qualitative_range_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_100'; +import chart_bullet_qualitative_range_ColorScale_200 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_200'; +import chart_bullet_qualitative_range_ColorScale_300 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_300'; +import chart_bullet_qualitative_range_ColorScale_400 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_400'; +import chart_bullet_qualitative_range_ColorScale_500 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_500'; + +// import global_Color_100 from '@patternfly/react-tokens/dist/esm/global_Color_100'; + +// Color scale +// See https://docs.google.com/document/d/1cw10pJFXWruB1SA8TQwituxn5Ss6KpxYPCOYGrH8qAY/edit +const COLOR_SCALE = [ + chart_bullet_qualitative_range_ColorScale_100.var, + chart_bullet_qualitative_range_ColorScale_200.var, + chart_bullet_qualitative_range_ColorScale_300.var, + chart_bullet_qualitative_range_ColorScale_400.var, + chart_bullet_qualitative_range_ColorScale_500.var +]; + +/** + * Blue color theme + * @private + */ +export const SkeletonColorTheme = ColorTheme({ + COLOR_SCALE +}); diff --git a/packages/react-charts/src/components/ChartTheme/themes/skeleton-theme.ts b/packages/react-charts/src/components/ChartTheme/themes/skeleton-theme.ts new file mode 100644 index 00000000000..f512ad1ad52 --- /dev/null +++ b/packages/react-charts/src/components/ChartTheme/themes/skeleton-theme.ts @@ -0,0 +1,180 @@ +/* eslint-disable camelcase */ +import chart_bullet_qualitative_range_ColorScale_100 from '@patternfly/react-tokens/dist/esm/chart_bullet_qualitative_range_ColorScale_100'; + +const DEFAULT_COLOR = chart_bullet_qualitative_range_ColorScale_100.var; + +// Labels +const LABEL_PROPS = { + fill: 'transparent', + stroke: 'transparent' +}; +const LABEL_CENTERED_PROPS = { + ...LABEL_PROPS +}; + +/** + * Victory theme properties only + * @private + */ +export const SkeletonTheme = { + skeleton: { + backgroundStyle: { + fill: DEFAULT_COLOR + }, + style: LABEL_CENTERED_PROPS + }, + area: { + style: { + data: { + fill: DEFAULT_COLOR + }, + labels: LABEL_CENTERED_PROPS + } + }, + axis: { + style: { + axis: { + fill: 'transparent', + stroke: DEFAULT_COLOR + }, + axisLabel: { + ...LABEL_CENTERED_PROPS, + fill: DEFAULT_COLOR, + stroke: 'transparent' + }, + grid: { + fill: 'transparent', + stroke: 'transparent' + }, + ticks: { + fill: 'transparent', + stroke: DEFAULT_COLOR + }, + tickLabels: { + ...LABEL_PROPS, + fill: 'transparent' + } + } + }, + bar: { + style: { + data: { + fill: DEFAULT_COLOR, + stroke: DEFAULT_COLOR + }, + labels: LABEL_PROPS + } + }, + boxplot: { + style: { + max: { + stroke: DEFAULT_COLOR + }, + maxLabels: LABEL_PROPS, + median: { + stroke: DEFAULT_COLOR + }, + medianLabels: LABEL_PROPS, + min: { + stroke: DEFAULT_COLOR + }, + minLabels: LABEL_PROPS, + q1: { + fill: DEFAULT_COLOR + }, + q1Labels: LABEL_PROPS, + q3: { + fill: DEFAULT_COLOR + }, + q3Labels: LABEL_PROPS + } + }, + candlestick: { + style: { + data: { + stroke: DEFAULT_COLOR + }, + labels: LABEL_CENTERED_PROPS + } + }, + chart: { + // TBD... + }, + errorbar: { + style: { + data: { + fill: 'transparent', + stroke: DEFAULT_COLOR + }, + labels: LABEL_CENTERED_PROPS + } + }, + group: { + // TBD... + }, + legend: { + style: { + labels: LABEL_PROPS, + title: { + ...LABEL_PROPS + } + } + }, + line: { + style: { + data: { + fill: 'transparent', + stroke: DEFAULT_COLOR + }, + labels: LABEL_CENTERED_PROPS + } + }, + pie: { + style: { + data: { + stroke: 'transparent' + }, + labels: { + ...LABEL_PROPS + } + } + }, + scatter: { + style: { + data: { + fill: DEFAULT_COLOR, + stroke: 'transparent' + }, + labels: LABEL_CENTERED_PROPS + } + }, + stack: { + // TBD... + }, + tooltip: { + flyoutStyle: { + fill: 'transparent', // background + stroke: 'transparent' // border + }, + style: { + fill: 'transparent' // text + } + }, + voronoi: { + style: { + data: { + fill: DEFAULT_COLOR, + stroke: DEFAULT_COLOR + }, + labels: { + ...LABEL_CENTERED_PROPS, + fill: 'transparent' // text + }, + // Note: These properties override tooltip + flyout: { + fill: 'transparent', // background + stroke: 'transparent' // border + } + } + } +}; diff --git a/packages/react-charts/src/components/ChartUtils/chart-theme-types.ts b/packages/react-charts/src/components/ChartUtils/chart-theme-types.ts index baeab5caae6..a9c569ee308 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-theme-types.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-theme-types.ts @@ -1,5 +1,3 @@ -import cloneDeep from 'lodash/cloneDeep'; - import { ChartThemeDefinition } from '../ChartTheme/ChartTheme'; import { ChartAxisTheme, @@ -17,9 +15,13 @@ import { ChartDonutUtilizationStaticTheme, ChartDonutThresholdDynamicTheme, ChartDonutThresholdStaticTheme, - ChartThresholdTheme + ChartThresholdTheme, + ChartSkeletonTheme } from '../ChartTheme/ChartThemeTypes'; import { getTheme, getCustomTheme } from './chart-theme'; +import { ChartThemeColor } from '../ChartTheme/ChartThemeColor'; +import merge from 'lodash/merge'; +import { SkeletonColorTheme } from '../ChartTheme/themes/colors/skeleton-theme'; /** * Returns axis theme @@ -38,22 +40,43 @@ export const getBulletTheme = (themeColor: string): ChartThemeDefinition => * Returns comparative error measure theme for bullet chart * @private */ -export const getBulletComparativeErrorMeasureTheme = (themeColor: string): ChartThemeDefinition => - getCustomTheme(themeColor, ChartBulletComparativeErrorMeasureTheme); +export const getBulletComparativeErrorMeasureTheme = (themeColor: string): ChartThemeDefinition => { + const theme = getCustomTheme(themeColor, ChartBulletComparativeErrorMeasureTheme); + + // Override zero measure + if (themeColor === ChartThemeColor.skeleton) { + theme.bar.style = merge(theme.bar.style, ChartSkeletonTheme.bar.style); + } + return theme; +}; /** * Returns comparative measure theme for bullet chart * @private */ -export const getBulletComparativeMeasureTheme = (themeColor: string): ChartThemeDefinition => - getCustomTheme(themeColor, ChartBulletComparativeMeasureTheme); +export const getBulletComparativeMeasureTheme = (themeColor: string): ChartThemeDefinition => { + const theme = getCustomTheme(themeColor, ChartBulletComparativeMeasureTheme); + + // Override zero measure + if (themeColor === ChartThemeColor.skeleton) { + theme.bar.style = merge(theme.bar.style, ChartSkeletonTheme.bar.style); + } + return theme; +}; /** * Returns comparative warning measure theme for bullet chart * @private */ -export const getBulletComparativeWarningMeasureTheme = (themeColor: string): ChartThemeDefinition => - getCustomTheme(themeColor, ChartBulletComparativeWarningMeasureTheme); +export const getBulletComparativeWarningMeasureTheme = (themeColor: string): ChartThemeDefinition => { + const theme = getCustomTheme(themeColor, ChartBulletComparativeWarningMeasureTheme); + + // Override zero measure + if (themeColor === ChartThemeColor.skeleton) { + theme.bar.style = merge(theme.bar.style, ChartSkeletonTheme.bar.style); + } + return theme; +}; /** * Returns group title theme for bullet chart @@ -73,8 +96,15 @@ export const getBulletPrimaryDotMeasureTheme = (themeColor: string): ChartThemeD * Returns primary negative measure theme for bullet chart * @private */ -export const getBulletPrimaryNegativeMeasureTheme = (themeColor: string): ChartThemeDefinition => - getCustomTheme(themeColor, ChartBulletPrimaryNegativeMeasureTheme); +export const getBulletPrimaryNegativeMeasureTheme = (themeColor: string): ChartThemeDefinition => { + const theme = getCustomTheme(themeColor, ChartBulletPrimaryNegativeMeasureTheme); + + // Override colorScale + if (themeColor === ChartThemeColor.skeleton) { + theme.group.colorScale = merge(theme.group.colorScale, SkeletonColorTheme.group.colorScale); + } + return theme; +}; /** * Returns primary segmented measure theme for bullet chart @@ -87,8 +117,15 @@ export const getBulletPrimarySegmentedMeasureTheme = (themeColor: string): Chart * Returns qualitative range theme for bullet chart * @private */ -export const getBulletQualitativeRangeTheme = (themeColor: string): ChartThemeDefinition => - getCustomTheme(themeColor, ChartBulletQualitativeRangeTheme); +export const getBulletQualitativeRangeTheme = (themeColor: string): ChartThemeDefinition => { + const theme = getCustomTheme(themeColor, ChartBulletQualitativeRangeTheme); + + // Override colorScale + if (themeColor === ChartThemeColor.skeleton) { + theme.group.colorScale = merge(theme.group.colorScale, SkeletonColorTheme.group.colorScale); + } + return theme; +}; /** * Returns theme for Chart component @@ -99,13 +136,13 @@ export const getChartTheme = (themeColor: string, showAxis: boolean): ChartTheme if (!showAxis) { theme.axis.padding = 0; - theme.axis.style.axis.fill = 'none'; - theme.axis.style.axis.stroke = 'none'; - theme.axis.style.grid.fill = 'none'; - theme.axis.style.grid.stroke = 'none'; - theme.axis.style.ticks.fill = 'none'; - theme.axis.style.ticks.stroke = 'none'; - theme.axis.style.tickLabels.fill = 'none'; + theme.axis.style.axis.fill = 'transparent'; + theme.axis.style.axis.stroke = 'transparent'; + theme.axis.style.grid.fill = 'transparent'; + theme.axis.style.grid.stroke = 'transparent'; + theme.axis.style.ticks.fill = 'transparent'; + theme.axis.style.ticks.stroke = 'transparent'; + theme.axis.style.tickLabels.fill = 'transparent'; } return theme; }; @@ -128,6 +165,12 @@ export const getDonutThresholdDynamicTheme = (themeColor: string): ChartThemeDef // Merge the threshold colors in case users want to show the unused data theme.pie.colorScale = [theme.pie.colorScale[0], ...ChartDonutThresholdStaticTheme.pie.colorScale]; + + // Override colorScale + if (themeColor === ChartThemeColor.skeleton) { + theme.legend.colorScale = merge(theme.legend.colorScale, SkeletonColorTheme.legend.colorScale); + theme.pie.colorScale = merge(theme.pie.colorScale, SkeletonColorTheme.pie.colorScale); + } return theme; }; @@ -136,11 +179,18 @@ export const getDonutThresholdDynamicTheme = (themeColor: string): ChartThemeDef * @private */ export const getDonutThresholdStaticTheme = (themeColor: string, invert?: boolean): ChartThemeDefinition => { - const staticTheme = cloneDeep(ChartDonutThresholdStaticTheme); - if (invert && staticTheme.pie.colorScale instanceof Array) { - staticTheme.pie.colorScale = staticTheme.pie.colorScale.reverse(); + const theme = getCustomTheme(themeColor, ChartDonutThresholdStaticTheme); + + if (invert && theme.pie.colorScale instanceof Array) { + const colorScale = [...ChartDonutThresholdStaticTheme.pie.colorScale]; + theme.pie.colorScale = merge(theme.pie.colorScale, colorScale.reverse()); } - return getCustomTheme(themeColor, staticTheme); + + // Override colorScale + if (themeColor === ChartThemeColor.skeleton) { + theme.pie.colorScale = merge(theme.pie.colorScale, SkeletonColorTheme.pie.colorScale); + } + return theme; }; /** @@ -151,8 +201,14 @@ export const getDonutUtilizationTheme = (themeColor: string): ChartThemeDefiniti const theme = getCustomTheme(themeColor, ChartDonutUtilizationDynamicTheme); // Merge just the first color of dynamic (blue, green, etc.) with static (grey) for expected colorScale - theme.pie.colorScale = [theme.pie.colorScale[0], ...ChartDonutUtilizationStaticTheme.pie.colorScale]; theme.legend.colorScale = [theme.legend.colorScale[0], ...ChartDonutUtilizationStaticTheme.legend.colorScale]; + theme.pie.colorScale = [theme.pie.colorScale[0], ...ChartDonutUtilizationStaticTheme.pie.colorScale]; + + // Override colorScale + if (themeColor === ChartThemeColor.skeleton) { + theme.legend.colorScale = merge(theme.legend.colorScale, SkeletonColorTheme.legend.colorScale); + theme.pie.colorScale = merge(theme.pie.colorScale, SkeletonColorTheme.pie.colorScale); + } return theme; }; diff --git a/packages/react-charts/src/components/ChartUtils/chart-theme.ts b/packages/react-charts/src/components/ChartUtils/chart-theme.ts index b8f7e41b0b7..7af122d23cd 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-theme.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-theme.ts @@ -1,12 +1,13 @@ import merge from 'lodash/merge'; import { ChartThemeColor } from '../ChartTheme/ChartThemeColor'; import { ChartThemeDefinition } from '../ChartTheme/ChartTheme'; -import { ChartBaseTheme } from '../ChartTheme/ChartThemeTypes'; +import { ChartBaseTheme, ChartSkeletonTheme } from '../ChartTheme/ChartThemeTypes'; import { BlueColorTheme } from '../ChartTheme/themes/colors/blue-theme'; import { CyanColorTheme } from '../ChartTheme/themes/colors/cyan-theme'; import { GoldColorTheme } from '../ChartTheme/themes/colors/gold-theme'; import { GrayColorTheme } from '../ChartTheme/themes/colors/gray-theme'; import { GreenColorTheme } from '../ChartTheme/themes/colors/green-theme'; +import { SkeletonColorTheme } from '../ChartTheme/themes/colors/skeleton-theme'; import { MultiColorOrderedTheme } from '../ChartTheme/themes/colors/multi-ordered-theme'; import { MultiColorUnorderedTheme } from '../ChartTheme/themes/colors/multi-unordered-theme'; import { OrangeColorTheme } from '../ChartTheme/themes/colors/orange-theme'; @@ -27,11 +28,18 @@ export const getCustomTheme = (themeColor: string, customTheme: ChartThemeDefini * @public */ export const getTheme = (themeColor: string): ChartThemeDefinition => { - // Deep clone const baseTheme = { - ...JSON.parse(JSON.stringify(ChartBaseTheme)) + ...JSON.parse(JSON.stringify(ChartBaseTheme)) // Deep clone }; - return merge(baseTheme, getThemeColors(themeColor)); + const skeletonTheme = + themeColor === ChartThemeColor.skeleton + ? { + ...JSON.parse(JSON.stringify(ChartSkeletonTheme)) // Deep clone + } + : {}; + const newTheme = merge(baseTheme, skeletonTheme); + + return merge(newTheme, getThemeColors(themeColor)); }; /** @@ -59,6 +67,8 @@ export const getThemeColors = (themeColor: string) => { return OrangeColorTheme; case ChartThemeColor.purple: return PurpleColorTheme; + case ChartThemeColor.skeleton: + return SkeletonColorTheme; default: return BlueColorTheme; } diff --git a/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md b/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md index 0e77eac5cbb..11e5ab5ca33 100644 --- a/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md +++ b/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md @@ -154,6 +154,7 @@ class MultiColorChart extends React.Component { this.containerRef = React.createRef(); this.observer = () => {}; this.state = { + extraHeight: 0, width: 0 }; this.handleResize = () => { diff --git a/packages/react-charts/src/components/Skeletons/examples/skeletons.md b/packages/react-charts/src/components/Skeletons/examples/skeletons.md new file mode 100644 index 00000000000..b3e57ac6737 --- /dev/null +++ b/packages/react-charts/src/components/Skeletons/examples/skeletons.md @@ -0,0 +1,796 @@ +--- +id: Skeletons +section: charts +propComponents: [ + 'Chart', + 'ChartArea', + 'ChartAxis', + 'ChartBar', + 'ChartBoxPlot', + 'ChartBullet', + 'ChartDonut', + 'ChartDonutThreshold', + 'ChartDonutUtilization', + 'ChartLegend', + 'ChartLine', + 'ChartGroup', + 'ChartPie', + 'ChartScatter', + 'ChartStack', + 'ChartThreshold', + 'ChartVoronoiContainer' +] +hideDarkMode: true +--- + +import { Chart, ChartArea, ChartAxis, ChartBar, ChartBoxPlot, ChartBullet, ChartDonut, ChartDonutThreshold, ChartDonutUtilization, ChartLegend, ChartLine, ChartGroup, ChartPie, ChartScatter, ChartStack, ChartThemeColor, ChartThreshold, ChartVoronoiContainer } from '@patternfly/react-charts'; +import { getResizeObserver } from '@patternfly/react-core'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; + +## Introduction +Note: PatternFly React charts live in its own package at [@patternfly/react-charts](https://www.npmjs.com/package/@patternfly/react-charts)! + +PatternFly React charts are based on the [Victory](https://formidable.com/open-source/victory/docs/victory-chart/) chart library, along with additional functionality, custom components, and theming for PatternFly. This provides a collection of React based components you can use to build PatternFly patterns with consistent markup, styling, and behavior. + +## Examples +### Area chart +```js +import React from 'react'; +import { Chart, ChartArea, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts'; + +export const ChartAreaSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea />} + legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }]} + legendOrientation="vertical" + legendPosition="right" + height={200} + maxDomain={{y: 9}} + name="chart1" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={800} + > + + + + + + + + +
+ + ); +} +``` + +### Bar chart +```js +import React from 'react'; +import { Chart, ChartBar, ChartAxis, ChartGroup, ChartVoronoiContainer } from '@patternfly/react-charts'; + +export const ChartBarSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea />} + domain={{y: [0,9]}} + domainPadding={{ x: [30, 25] }} + legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} + legendOrientation="vertical" + legendPosition="right" + height={250} + name="chart1" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={600} + > + + + + + + + + + +
+ + ); +} +``` + +### Box plot chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartBoxPlot } from '@patternfly/react-charts'; + +export const ChartBoxPlotSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ + + + + +
+ + ); +} +``` + +### Bullet chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartBullet, ChartLegend } from '@patternfly/react-charts'; + +export const ChartBulletSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} + legendComponent={} + maxDomain={{y: 100}} + name="chart2" + padding={{ + bottom: 50, + left: 150, // Adjusted to accommodate labels + right: 50, + top: 50 + }} + primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} + primarySegmentedMeasureLegendData={[{ name: 'Measure' }, { name: 'Measure' }]} + qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} + qualitativeRangeLegendData={[{ name: 'Range' }, { name: 'Range' }]} + subTitle="Details" + title="Text label" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={600} + /> +
+ + ); +} +``` + +### Donut chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartDonut } from '@patternfly/react-charts'; + +export const ChartDonutSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.x}: ${datum.y}%`} + name="chart1" + subTitle="Pets" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + title="100" + /> +
+ + ); +} +``` + +### Donut utilization chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartDonutUtilization } from '@patternfly/react-charts'; + +export const ChartDonutUtilizationSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ datum.x ? `${datum.x}: ${datum.y}%` : null} + legendData={[{ name: `Storage capacity: 75%` }, { name: 'Unused' }]} + legendOrientation="vertical" + name="chart2" + padding={{ + bottom: 20, + left: 20, + right: 225, // Adjusted to accommodate legend + top: 20 + }} + subTitle="of 100 GBps" + title="35%" + thresholds={[{ value: 60 }, { value: 90 }]} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={435} + /> +
+ + ); +} +``` + +### Donut utilization threshold +```js +import React from 'react'; +import { Chart, ChartAxis, ChartDonutThreshold, ChartDonutUtilization } from '@patternfly/react-charts'; + +export const ChartDonutUtilizationSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ datum.x ? datum.x : null} + name="chart10" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + > + datum.x ? `${datum.x}: ${datum.y}%` : null} + subTitle="of 100 GBps" + title="45%" + /> + +
+ + ); +} +``` + +### Line chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartLine } from '@patternfly/react-charts'; + +export const ChartLineSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea />} + legendData={[{ name: 'Cats' }, { name: 'Dogs', symbol: { type: 'dash' } }, { name: 'Birds' }, { name: 'Mice' }]} + legendOrientation="vertical" + legendPosition="right" + height={250} + maxDomain={{y: 10}} + minDomain={{y: 0}} + name="chart1" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={600} + > + + + + + + + + + +
+ + ); +} +``` + +### Pie chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartPie } from '@patternfly/react-charts'; + +export const ChartPieSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.x}: ${datum.y}`} + legendData={[{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }]} + legendOrientation="vertical" + legendPosition="right" + name="chart1" + padding={{ + bottom: 20, + left: 20, + right: 140, // Adjusted to accommodate legend + top: 20 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={350} + /> +
+ + ); +} +``` + +### Scatter chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartScatter } from '@patternfly/react-charts'; + +export const ChartScatterSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} + constrainToVisibleArea + /> + } + height={275} + maxDomain={{y: 8}} + minDomain={{y: 0}} + name="chart1" + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={450} + > + + + + + + +
+ + ); +} +``` + +### Stack chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartStack } from '@patternfly/react-charts'; + +export const ChartStackSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} constrainToVisibleArea />} + domainPadding={{ x: [30, 25] }} + legendData={[{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }]} + legendOrientation="vertical" + legendPosition="right" + height={250} + name="chart1" + padding={{ + bottom: 50, + left: 50, + right: 200, // Adjusted to accommodate legend + top: 50 + }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={600} + > + + + + + + + + + +
+ + ); +} +``` + +### Threshold chart +```js +import React from 'react'; +import { Chart, ChartAxis, ChartThreshold } from '@patternfly/react-charts'; +import chart_color_blue_300 from '@patternfly/react-tokens/dist/esm/chart_color_blue_300'; + +export const ChartThresholdSkeleton: React.FunctionComponent = () => { + const [isChecked, setIsChecked] = React.useState(true); + + const handleChange = (_event: React.FormEvent, checked: boolean) => { + setIsChecked(checked); + }; + + return ( + <> + +
+ `${datum.name}: ${datum.y}`} + constrainToVisibleArea + /> + } + legendPosition="bottom-left" + legendComponent={ + + } + height={250} + padding={{ + bottom: 100, // Adjusted to accomodate legend + left: 50, + right: 50, + top: 50 + }} + maxDomain={{ y: 9 }} + themeColor={isChecked ? ChartThemeColor.skeleton : ChartThemeColor.blue} + width={800} + > + + + + + + + + +
+ + ); +} +``` + +## Documentation +### Tips +- It's best for skeletons not to include interactions such as tooltips, cursors, interactive legends, etc. +- See Victory's [FAQ](https://formidable.com/open-source/victory/docs/faq) +- For single data points or zero values, you may want to set the `domain` prop +- `ChartLegend` may be used as a standalone component, instead of using `legendData` +- The `theme` and `themeColor` props should be applied at the most top level component +- Use `ChartGroup` to apply theme color scales and other properties to multiple components + +### Note +Currently, the generated documentation below is not able to resolve type definitions from Victory imports. For the +components used in the examples above, Victory pass-thru props are also documented here: + +- For `Chart` props, see [VictoryChart](https://formidable.com/open-source/victory/docs/victory-chart) +- For `ChartArea` props, see [VictoryArea](https://formidable.com/open-source/victory/docs/victory-area) +- For `ChartAxis` props, see [VictoryAxis](https://formidable.com/open-source/victory/docs/victory-axis) +- For `ChartBar` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartBoxPlot` props, see [VictoryBoxPlot](https://formidable.com/open-source/victory/docs/victory-box-plot) +- For `ChartBullet` props, see [VictoryBar](https://formidable.com/open-source/victory/docs/victory-bar) +- For `ChartDonut` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartDonutThreshold` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartDonutUtilization` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartLine` props, see [Victoryline](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartGroup` props, see [VictoryGroup](https://formidable.com/open-source/victory/docs/victory-group) +- For `ChartPie` props, see [VictoryPie](https://formidable.com/open-source/victory/docs/victory-pie) +- For `ChartScatter` props, see [VictoryScatter](https://formidable.com/open-source/victory/docs/victory-scatter) +- For `ChartStack` props, see [VictoryStack](https://formidable.com/open-source/victory/docs/victory-stack) +- For `ChartThreshold` props, see [VictoryLine](https://formidable.com/open-source/victory/docs/victory-line) +- For `ChartVoronoiContainer` props, see [VictoryVoronoiContainer](https://formidable.com/open-source/victory/docs/victory-voronoi-container)