{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"chart","type":"registry:ui","title":"Chart","description":"Tailark Base UI Chart component","dependencies":["recharts"],"registryDependencies":["@tailark/core-utils"],"files":[{"path":"ui/chart.tsx","type":"registry:ui","target":"@ui/chart.tsx","content":"'use client'\n\nimport * as React from 'react'\nimport type { ComponentType, ReactNode, CSSProperties } from 'react'\nimport * as RechartsPrimitive from 'recharts'\n\nimport { cn } from '@/lib/utils'\n\n// Format: { THEME_NAME: CSS_SELECTOR }\nconst THEMES = { light: '', dark: '.dark' } as const\n\nexport type ChartConfig = {\n    [k in string]: {\n        label?: ReactNode\n        icon?: ComponentType\n    } & ({ color?: string; theme?: never } | { color?: never; theme: Record<keyof typeof THEMES, string> })\n}\n\ntype ChartContextProps = {\n    config: ChartConfig\n}\n\nconst ChartContext = React.createContext<ChartContextProps | null>(null)\n\nfunction useChart() {\n    const context = React.useContext(ChartContext)\n\n    if (!context) {\n        throw new Error('useChart must be used within a <ChartContainer />')\n    }\n\n    return context\n}\n\nfunction ChartContainer({\n    id,\n    className,\n    children,\n    config,\n    ...props\n}: React.ComponentProps<'div'> & {\n    config: ChartConfig\n    children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>['children']\n}) {\n    const uniqueId = React.useId()\n    const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`\n\n    return (\n        <ChartContext.Provider value={{ config }}>\n            <div\n                data-slot=\"chart\"\n                data-chart={chartId}\n                className={cn(\n                    \"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-surface]:outline-hidden flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-sector[stroke='#fff']]:stroke-transparent\",\n                    className\n                )}\n                {...props}>\n                <ChartStyle\n                    id={chartId}\n                    config={config}\n                />\n                <RechartsPrimitive.ResponsiveContainer>{children}</RechartsPrimitive.ResponsiveContainer>\n            </div>\n        </ChartContext.Provider>\n    )\n}\n\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\n    const colorConfig = Object.entries(config).filter(([, config]) => config.theme || config.color)\n\n    if (!colorConfig.length) {\n        return null\n    }\n\n    return (\n        <style\n            dangerouslySetInnerHTML={{\n                __html: Object.entries(THEMES)\n                    .map(\n                        ([theme, prefix]) => `\n${prefix} [data-chart=${id}] {\n${colorConfig\n    .map(([key, itemConfig]) => {\n        const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || itemConfig.color\n        return color ? `  --color-${key}: ${color};` : null\n    })\n    .join('\\n')}\n}\n`\n                    )\n                    .join('\\n'),\n            }}\n        />\n    )\n}\n\nconst ChartTooltip = RechartsPrimitive.Tooltip\n\nfunction ChartTooltipContent({\n    active,\n    payload,\n    className,\n    indicator = 'dot',\n    hideLabel = false,\n    hideIndicator = false,\n    label,\n    labelFormatter,\n    labelClassName,\n    formatter,\n    color,\n    nameKey,\n    labelKey,\n}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &\n    React.ComponentProps<'div'> & {\n        hideLabel?: boolean\n        hideIndicator?: boolean\n        indicator?: 'line' | 'dot' | 'dashed'\n        nameKey?: string\n        labelKey?: string\n    }) {\n    const { config } = useChart()\n\n    const tooltipLabel = React.useMemo(() => {\n        if (hideLabel || !payload?.length) {\n            return null\n        }\n\n        const [item] = payload\n        const key = `${labelKey || item.dataKey || item.name || 'value'}`\n        const itemConfig = getPayloadConfigFromPayload(config, item, key)\n        const value = !labelKey && typeof label === 'string' ? config[label as keyof typeof config]?.label || label : itemConfig?.label\n\n        if (labelFormatter) {\n            return <div className={cn('font-medium', labelClassName)}>{labelFormatter(value, payload)}</div>\n        }\n\n        if (!value) {\n            return null\n        }\n\n        return <div className={cn('font-medium', labelClassName)}>{value}</div>\n    }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey])\n\n    if (!active || !payload?.length) {\n        return null\n    }\n\n    const nestLabel = payload.length === 1 && indicator !== 'dot'\n\n    return (\n        <div className={cn('border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl', className)}>\n            {!nestLabel ? tooltipLabel : null}\n            <div className=\"grid gap-1.5\">\n                {payload.map((item, index) => {\n                    const key = `${nameKey || item.name || item.dataKey || 'value'}`\n                    const itemConfig = getPayloadConfigFromPayload(config, item, key)\n                    const indicatorColor = color || item.payload.fill || item.color\n\n                    return (\n                        <div\n                            key={item.dataKey}\n                            className={cn('[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5', indicator === 'dot' && 'items-center')}>\n                            {formatter && item?.value !== undefined && item.name ? (\n                                formatter(item.value, item.name, item, index, item.payload)\n                            ) : (\n                                <>\n                                    {itemConfig?.icon ? (\n                                        <itemConfig.icon />\n                                    ) : (\n                                        !hideIndicator && (\n                                            <div\n                                                className={cn('border-(--color-border) bg-(--color-bg) shrink-0 rounded-[2px]', {\n                                                    'h-2.5 w-2.5': indicator === 'dot',\n                                                    'w-1': indicator === 'line',\n                                                    'w-0 border-[1.5px] border-dashed bg-transparent': indicator === 'dashed',\n                                                    'my-0.5': nestLabel && indicator === 'dashed',\n                                                })}\n                                                style={{\n                                                    '--color-bg': indicatorColor,\n                                                    '--color-border': indicatorColor,\n                                                } as CSSProperties}\n                                            />\n                                        )\n                                    )}\n                                    <div className={cn('flex flex-1 justify-between leading-none', nestLabel ? 'items-end' : 'items-center')}>\n                                        <div className=\"grid gap-1.5\">\n                                            {nestLabel ? tooltipLabel : null}\n                                            <span className=\"text-muted-foreground\">{itemConfig?.label || item.name}</span>\n                                        </div>\n                                        {item.value && <span className=\"text-foreground font-mono font-medium tabular-nums\">{item.value.toLocaleString()}</span>}\n                                    </div>\n                                </>\n                            )}\n                        </div>\n                    )\n                })}\n            </div>\n        </div>\n    )\n}\n\nconst ChartLegend = RechartsPrimitive.Legend\n\nfunction ChartLegendContent({\n    className,\n    hideIcon = false,\n    payload,\n    verticalAlign = 'bottom',\n    nameKey,\n}: React.ComponentProps<'div'> &\n    Pick<RechartsPrimitive.LegendProps, 'payload' | 'verticalAlign'> & {\n        hideIcon?: boolean\n        nameKey?: string\n    }) {\n    const { config } = useChart()\n\n    if (!payload?.length) {\n        return null\n    }\n\n    return (\n        <div className={cn('flex items-center justify-center gap-4', verticalAlign === 'top' ? 'pb-3' : 'pt-3', className)}>\n            {payload.map((item) => {\n                const key = `${nameKey || item.dataKey || 'value'}`\n                const itemConfig = getPayloadConfigFromPayload(config, item, key)\n\n                return (\n                    <div\n                        key={item.value}\n                        className={cn('[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3')}>\n                        {itemConfig?.icon && !hideIcon ? (\n                            <itemConfig.icon />\n                        ) : (\n                            <div\n                                className=\"h-2 w-2 shrink-0 rounded-[2px]\"\n                                style={{\n                                    backgroundColor: item.color,\n                                }}\n                            />\n                        )}\n                        {itemConfig?.label}\n                    </div>\n                )\n            })}\n        </div>\n    )\n}\n\n// Helper to extract item config from a payload.\nfunction getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: string) {\n    if (typeof payload !== 'object' || payload === null) {\n        return undefined\n    }\n\n    const payloadPayload = 'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null ? payload.payload : undefined\n\n    let configLabelKey: string = key\n\n    if (key in payload && typeof payload[key as keyof typeof payload] === 'string') {\n        configLabelKey = payload[key as keyof typeof payload] as string\n    } else if (payloadPayload && key in payloadPayload && typeof payloadPayload[key as keyof typeof payloadPayload] === 'string') {\n        configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string\n    }\n\n    return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config]\n}\n\nexport { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle }\n"}]}