import * as React from "react"; import { Path, type PathProps, type SkPath } from "@shopify/react-native-skia"; import type { ChartBounds, PointsArray } from "../../types"; import type { PathAnimationConfig } from "../../hooks/useAnimatedPath"; import { AnimatedPath } from "./AnimatedPath"; import { useBarGroupPaths } from "../hooks/useBarGroupPaths"; import type { RoundedCorners } from "../../utils/createRoundedRectPath"; import { useFunctionRef } from "../../hooks/useFunctionRef"; type BarGroupProps = { chartBounds: ChartBounds; betweenGroupPadding?: number; withinGroupPadding?: number; roundedCorners?: RoundedCorners; children: React.ReactElement[]; barWidth?: number; barCount?: number; onBarSizeChange?: (values: { barWidth: number; groupWidth: number; gapWidth: number; }) => void; }; export function BarGroup({ betweenGroupPadding = 0.25, withinGroupPadding = 0.25, chartBounds, roundedCorners, children, onBarSizeChange, barWidth: customBarWidth, barCount, }: BarGroupProps) { // Collect the bar props const bars = [] as BarGroupBarProps[]; React.Children.forEach(children, (child) => { if (React.isValidElement(child)) { if (child.type === BarGroupBar) { bars.push(child.props as BarGroupBarProps); } } }); const { paths, barWidth, groupWidth, gapWidth } = useBarGroupPaths( bars.map((bar) => bar.points), chartBounds, betweenGroupPadding, withinGroupPadding, roundedCorners, customBarWidth, barCount, ); // Handle bar size change const onBarSizeChangeRef = useFunctionRef(onBarSizeChange); React.useEffect(() => { onBarSizeChangeRef.current?.({ barWidth, groupWidth, gapWidth }); }, [barWidth, gapWidth, groupWidth, onBarSizeChangeRef]); // If no bars, short-circuit const firstBar = bars[0]; if (!firstBar) return null; return bars.map((props, i) => React.createElement(BarGroupBar, { ...props, // @ts-ignore __path: paths[i], key: i, }), ); } BarGroup.Bar = BarGroupBar; /** * Bar */ type BarGroupBarProps = { points: PointsArray; animate?: PathAnimationConfig; } & Partial>; function BarGroupBar(props: React.PropsWithChildren) { const { animate, ...rest } = props; // Props that come from BarGroup but aren't exposed publicly. // @ts-ignore const path = props.__path as SkPath; return React.createElement(animate ? AnimatedPath : Path, { path, style: "fill", color: "red", ...rest, ...(Boolean(animate) && { animate }), }); }