import { mobileVisualisationPalette } from '@hero-design/colors'; import { useMemo } from 'react'; import type { DataValue, Series, StyleConfig } from '../../types'; import { ERROR_COLOR_NOT_FOUND, ERROR_COLOR_NUMBER_MISMATCH, } from '../constants'; import { filterElementHasNoColor } from '../utils'; import useColorScale from './useColorScale'; /** * Props for the useCustomColor hook */ type useCustomColorProps = { /** Array of data series containing values and labels */ data: Array>>; /** Optional configuration for custom series colors */ seriesConfig?: StyleConfig['series']; }; /** * Hook to handle custom color assignments for chart series * * This hook manages: * 1. Validation of custom color configurations * 2. Color mapping between series and palette * 3. Fallback to default colors when custom colors aren't provided * * @throws {Error} When custom colors are invalid or don't match data series */ const useCustomColor = ({ data, seriesConfig }: useCustomColorProps) => { // Check if custom colors are provided and non-empty const hasCustomColors = Boolean(seriesConfig?.length); // Process and validate custom color segments const customSegments = useMemo(() => { if (!hasCustomColors) return undefined; // Filter out segments without colors const filtered = filterElementHasNoColor(seriesConfig || []); // Validate: number of custom colors must match number of data series if (filtered.length < data.length) { throw new Error(ERROR_COLOR_NUMBER_MISMATCH); } // Validate: all data series must have corresponding custom colors const dataLabels = new Set(data.map((d) => d.label)); if (!filtered.every((series) => dataLabels.has(series.label))) { throw new Error(ERROR_COLOR_NUMBER_MISMATCH); } return filtered; }, [seriesConfig, hasCustomColors, data]); // Map custom segments to actual color values from palette const customColors = useMemo(() => { if (!customSegments) return []; // Convert color keys to actual color values const colors = customSegments.map((series) => { const color = mobileVisualisationPalette[series.color]; // Validate: color key must exist in palette if (color === undefined) { throw new Error(ERROR_COLOR_NOT_FOUND.replace('{color}', series.color)); } return color; }); return colors; }, [customSegments]); // Create color scale: // - If custom colors exist, use custom color mapping // - Otherwise, fall back to default color mapping return useColorScale( customSegments ? customSegments.map((series) => series.label) : data.map((series) => series.label), customColors ); }; export default useCustomColor;