@thesage/charts 0.1.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.
@@ -0,0 +1,23 @@
1
+
2
+ 
3
+ > @thesage/charts@0.1.0 build /Users/shalomormsby/Developer/work/ecosystem/packages/charts
4
+ > tsup src/index.ts --format cjs,esm --dts
5
+
6
+ CLI Building entry: src/index.ts
7
+ CLI Using tsconfig: tsconfig.json
8
+ CLI tsup v8.5.1
9
+ CLI Using tsup config: /Users/shalomormsby/Developer/work/ecosystem/packages/charts/tsup.config.ts
10
+ CLI Target: es2020
11
+ CLI Cleaning output folder
12
+ CJS Build start
13
+ ESM Build start
14
+ ESM dist/index.mjs 4.07 KB
15
+ ESM dist/index.mjs.map 17.06 KB
16
+ ESM ⚡️ Build success in 38ms
17
+ CJS dist/index.js 4.97 KB
18
+ CJS dist/index.js.map 17.21 KB
19
+ CJS ⚡️ Build success in 38ms
20
+ DTS Build start
21
+ DTS ⚡️ Build success in 1352ms
22
+ DTS dist/index.d.ts 2.37 KB
23
+ DTS dist/index.d.mts 2.37 KB
@@ -0,0 +1,6 @@
1
+
2
+ > @sage/charts@0.1.0 lint /Users/shalomormsby/Developer/work/ecosystem/packages/charts
3
+ > eslint src/
4
+
5
+ sh: eslint: command not found
6
+  ELIFECYCLE  Command failed.
@@ -0,0 +1,59 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { ResponsiveContainer, Tooltip, Legend } from 'recharts';
4
+ export * from 'recharts';
5
+
6
+ declare const THEMES: {
7
+ readonly light: {
8
+ readonly '--color-chart-1': "12 76% 61%";
9
+ readonly '--color-chart-2': "173 58% 39%";
10
+ readonly '--color-chart-3': "197 37% 24%";
11
+ readonly '--color-chart-4': "43 74% 66%";
12
+ readonly '--color-chart-5': "27 87% 67%";
13
+ };
14
+ readonly dark: {
15
+ readonly '--color-chart-1': "220 70% 50%";
16
+ readonly '--color-chart-2': "160 60% 45%";
17
+ readonly '--color-chart-3': "30 80% 55%";
18
+ readonly '--color-chart-4': "280 65% 60%";
19
+ readonly '--color-chart-5': "340 75% 55%";
20
+ };
21
+ };
22
+ type ChartConfig = {
23
+ [k in string]: {
24
+ label?: React.ReactNode;
25
+ icon?: React.ComponentType;
26
+ color?: string;
27
+ theme?: Record<keyof typeof THEMES, string>;
28
+ };
29
+ };
30
+ declare const ChartContainer: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
31
+ config: ChartConfig;
32
+ children: React.ComponentProps<typeof ResponsiveContainer>["children"];
33
+ }, "ref"> & React.RefAttributes<HTMLDivElement>>;
34
+ declare const ChartStyle: ({ id, config }: {
35
+ id: string;
36
+ config: ChartConfig;
37
+ }) => react_jsx_runtime.JSX.Element | null;
38
+ declare const ChartTooltip: typeof Tooltip;
39
+ declare const ChartTooltipContent: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
40
+ hideLabel?: boolean;
41
+ hideIndicator?: boolean;
42
+ indicator?: "line" | "dot" | "dashed";
43
+ nameKey?: string;
44
+ labelKey?: string;
45
+ active?: boolean;
46
+ payload?: any[];
47
+ label?: any;
48
+ labelFormatter?: (label: any, payload: any[]) => React.ReactNode;
49
+ config?: ChartConfig;
50
+ }, "ref"> & React.RefAttributes<HTMLDivElement>>;
51
+ declare const ChartLegend: typeof Legend;
52
+ declare const ChartLegendContent: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
53
+ hideIcon?: boolean;
54
+ nameKey?: string;
55
+ verticalAlign?: "top" | "bottom" | "middle";
56
+ payload?: any[];
57
+ }, "ref"> & React.RefAttributes<HTMLDivElement>>;
58
+
59
+ export { type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent };
@@ -0,0 +1,59 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { ResponsiveContainer, Tooltip, Legend } from 'recharts';
4
+ export * from 'recharts';
5
+
6
+ declare const THEMES: {
7
+ readonly light: {
8
+ readonly '--color-chart-1': "12 76% 61%";
9
+ readonly '--color-chart-2': "173 58% 39%";
10
+ readonly '--color-chart-3': "197 37% 24%";
11
+ readonly '--color-chart-4': "43 74% 66%";
12
+ readonly '--color-chart-5': "27 87% 67%";
13
+ };
14
+ readonly dark: {
15
+ readonly '--color-chart-1': "220 70% 50%";
16
+ readonly '--color-chart-2': "160 60% 45%";
17
+ readonly '--color-chart-3': "30 80% 55%";
18
+ readonly '--color-chart-4': "280 65% 60%";
19
+ readonly '--color-chart-5': "340 75% 55%";
20
+ };
21
+ };
22
+ type ChartConfig = {
23
+ [k in string]: {
24
+ label?: React.ReactNode;
25
+ icon?: React.ComponentType;
26
+ color?: string;
27
+ theme?: Record<keyof typeof THEMES, string>;
28
+ };
29
+ };
30
+ declare const ChartContainer: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
31
+ config: ChartConfig;
32
+ children: React.ComponentProps<typeof ResponsiveContainer>["children"];
33
+ }, "ref"> & React.RefAttributes<HTMLDivElement>>;
34
+ declare const ChartStyle: ({ id, config }: {
35
+ id: string;
36
+ config: ChartConfig;
37
+ }) => react_jsx_runtime.JSX.Element | null;
38
+ declare const ChartTooltip: typeof Tooltip;
39
+ declare const ChartTooltipContent: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
40
+ hideLabel?: boolean;
41
+ hideIndicator?: boolean;
42
+ indicator?: "line" | "dot" | "dashed";
43
+ nameKey?: string;
44
+ labelKey?: string;
45
+ active?: boolean;
46
+ payload?: any[];
47
+ label?: any;
48
+ labelFormatter?: (label: any, payload: any[]) => React.ReactNode;
49
+ config?: ChartConfig;
50
+ }, "ref"> & React.RefAttributes<HTMLDivElement>>;
51
+ declare const ChartLegend: typeof Legend;
52
+ declare const ChartLegendContent: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
53
+ hideIcon?: boolean;
54
+ nameKey?: string;
55
+ verticalAlign?: "top" | "bottom" | "middle";
56
+ payload?: any[];
57
+ }, "ref"> & React.RefAttributes<HTMLDivElement>>;
58
+
59
+ export { type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent };
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";var V=Object.create;var y=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var A=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var O=(t,e)=>{for(var o in e)y(t,o,{get:e[o],enumerable:!0})},v=(t,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of z(e))!F.call(t,n)&&n!==o&&y(t,n,{get:()=>e[n],enumerable:!(r=q(e,n))||r.enumerable});return t},x=(t,e,o)=>(v(t,e,"default"),o&&v(o,e,"default")),W=(t,e,o)=>(o=t!=null?V(A(t)):{},v(e||!t||!t.__esModule?y(o,"default",{value:t,enumerable:!0}):o,t)),B=t=>v(y({},"__esModule",{value:!0}),t);var m={};O(m,{ChartContainer:()=>S,ChartLegend:()=>J,ChartLegendContent:()=>H,ChartStyle:()=>_,ChartTooltip:()=>G,ChartTooltipContent:()=>j});module.exports=B(m);var l=W(require("react")),u=require("recharts");var T=require("clsx"),E=require("tailwind-merge");function c(...t){return(0,E.twMerge)((0,T.clsx)(t))}var a=require("react/jsx-runtime");var M=l.createContext(null);function $(){let t=l.useContext(M);if(!t)throw new Error("useChart must be used within a <ChartContainer />");return t}var S=l.forwardRef(({id:t,className:e,children:o,config:r,...n},d)=>{let f=l.useId(),i=`chart-${t||f.replace(/:/g,"")}`;return(0,a.jsx)(M.Provider,{value:{config:r},children:(0,a.jsxs)("div",{"data-chart":i,ref:d,className:c("flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-[var(--color-text-secondary)] [&_.recharts-cartesian-grid_line]:stroke-[var(--color-border)]",e),...n,children:[(0,a.jsx)(_,{id:i,config:r}),(0,a.jsx)(u.ResponsiveContainer,{children:o})]})})});S.displayName="ChartContainer";var _=({id:t,config:e})=>{let o=Object.entries(e).filter(([r,n])=>n.theme||n.color);return o.length?(0,a.jsx)("style",{dangerouslySetInnerHTML:{__html:`
2
+ [data-chart=${t}] {
3
+ ${o.map(([r,n])=>{let d=n.theme||n.color;return d?`--color-${r}: ${d};`:null}).join(`
4
+ `)}
5
+ }
6
+ `}}):null},G=u.Tooltip,j=l.forwardRef(({active:t,payload:e,className:o,indicator:r="dot",hideLabel:n=!1,hideIndicator:d=!1,label:f,labelFormatter:i,config:b,nameKey:R,labelKey:g},K)=>{let{config:D}=$(),h=b||D,k=l.useMemo(()=>{if(n||!e||!e.length)return null;let[s]=e,N=`${g||s.dataKey||s.name||"value"}`,w=P(h,s,N),p=!g&&typeof f=="string"?h[f]?.label||f:w?.label;return i?(0,a.jsx)("div",{className:c("font-medium"),children:i(p,e)}):p?(0,a.jsx)("div",{className:c("font-medium"),children:p}):null},[f,i,e,n,g,h]);if(!t||!e?.length)return null;let C=e.length===1&&r!=="dot";return(0,a.jsxs)("div",{ref:K,className:c("grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] px-2.5 py-1.5 text-xs shadow-xl transition-all ease-in-out animate-in fade-in-0 zoom-in-95",o),children:[C?null:k,(0,a.jsx)("div",{className:"grid gap-1.5",children:e.map((s,N)=>{let w=`${R||s.name||s.dataKey||"value"}`,p=P(h,s,w),L=I(s.payload.fill||s.color);return(0,a.jsxs)("div",{className:c("flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",r==="dot"&&"items-center"),children:[r&&!d&&(0,a.jsx)("div",{className:c("shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",{"h-2.5 w-2.5":r==="dot","w-1":r==="line","w-0 border-[1.5px] border-dashed bg-transparent":r==="dashed","my-0.5":C&&r==="dashed"}),style:{"--color-bg":L,"--color-border":L}}),(0,a.jsxs)("div",{className:c("flex flex-1 justify-between leading-none",C?"items-end":"items-center"),children:[(0,a.jsxs)("div",{className:"grid gap-1.5",children:[C?k:null,(0,a.jsx)("span",{className:"text-[var(--color-text-secondary)]",children:p?.label||s.name})]}),s.value&&(0,a.jsx)("span",{className:"font-mono font-medium tabular-nums text-[var(--color-text-primary)]",children:s.value.toLocaleString()})]})]},s.dataKey||N)})})]})});j.displayName="ChartTooltipContent";var J=u.Legend,H=l.forwardRef(({className:t,hideIcon:e=!1,payload:o,verticalAlign:r="bottom",nameKey:n},d)=>{let{config:f}=$();return o?.length?(0,a.jsx)("div",{ref:d,className:c("flex items-center justify-center gap-4",r==="top"?"pb-3":"pt-3",t),children:o.map(i=>{let b=`${n||i.dataKey||"value"}`,R=P(f,i,b),g=I(i.color);return(0,a.jsxs)("div",{className:c("flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"),children:[!e&&(0,a.jsx)("div",{className:"h-2 w-2 shrink-0 rounded-[2px]",style:{backgroundColor:g}}),(0,a.jsx)("span",{className:"text-sm text-[var(--color-text-primary)]",children:R?.label||i.value})]},i.value)})}):null});H.displayName="ChartLegendContent";function P(t,e,o){if(typeof e!="object"||e===null)return;let r="payload"in e&&typeof e.payload=="object"&&e.payload!==null?e.payload:void 0,n=o;return o in e&&typeof e[o]=="string"?n=e[o]:r&&o in r&&typeof r[o]=="string"&&(n=r[o]),n in t?t[n]:t[o]}function I(t){return t?(t.startsWith("var(--"),t):"var(--color-primary)"}x(m,require("recharts"),module.exports);0&&(module.exports={ChartContainer,ChartLegend,ChartLegendContent,ChartStyle,ChartTooltip,ChartTooltipContent,...require("recharts")});
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/components/chart.tsx","../src/lib/utils.ts"],"sourcesContent":["export * from './components/chart';\nexport * from 'recharts';\n\n// Override specific recharts exports if we wrapped them, \n// otherwise we just export the primitives and let usage include regular recharts components.\n","'use client';\n\nimport * as React from 'react';\nimport { ResponsiveContainer, Legend, Tooltip } from 'recharts';\nimport { cn } from '../lib/utils';\n\n// Format: { THEME_NAME: { cssVariable: string; value: string } }\nconst THEMES = {\n light: {\n '--color-chart-1': '12 76% 61%',\n '--color-chart-2': '173 58% 39%',\n '--color-chart-3': '197 37% 24%',\n '--color-chart-4': '43 74% 66%',\n '--color-chart-5': '27 87% 67%',\n },\n dark: {\n '--color-chart-1': '220 70% 50%',\n '--color-chart-2': '160 60% 45%',\n '--color-chart-3': '30 80% 55%',\n '--color-chart-4': '280 65% 60%',\n '--color-chart-5': '340 75% 55%',\n },\n} as const;\n\nexport type ChartConfig = {\n [k in string]: {\n label?: React.ReactNode;\n icon?: React.ComponentType;\n color?: string;\n theme?: Record<keyof typeof THEMES, string>;\n }\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\nconst ChartContainer = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n config: ChartConfig;\n children: React.ComponentProps<typeof ResponsiveContainer>['children'];\n }\n>(({ id, className, children, config, ...props }, ref) => {\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-chart={chartId}\n ref={ref}\n className={cn(\n \"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-[var(--color-text-secondary)] [&_.recharts-cartesian-grid_line]:stroke-[var(--color-border)]\",\n className\n )}\n {...props}\n >\n <ChartStyle id={chartId} config={config} />\n <ResponsiveContainer>\n {children}\n </ResponsiveContainer>\n </div>\n </ChartContext.Provider>\n );\n});\nChartContainer.displayName = 'ChartContainer';\n\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\n const colorConfig = Object.entries(config).filter(\n ([_, value]) => value.theme || value.color\n );\n\n if (!colorConfig.length) {\n return null;\n }\n\n return (\n <style dangerouslySetInnerHTML={{\n __html: `\n [data-chart=${id}] {\n ${colorConfig\n .map(([key, item]) => {\n const color = item.theme || item.color;\n return color ? `--color-${key}: ${color};` : null;\n })\n .join('\\n')}\n }\n `\n }} />\n );\n};\n\n// -- Tooltip --\n\nconst ChartTooltip = Tooltip;\n\nconst ChartTooltipContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n hideLabel?: boolean;\n hideIndicator?: boolean;\n indicator?: 'line' | 'dot' | 'dashed';\n nameKey?: string;\n labelKey?: string;\n active?: boolean;\n payload?: any[];\n label?: any;\n labelFormatter?: (label: any, payload: any[]) => React.ReactNode;\n config?: ChartConfig;\n }\n>(({ active, payload, className, indicator = 'dot', hideLabel = false, hideIndicator = false, label, labelFormatter, config, nameKey, labelKey }, ref) => {\n const { config: configFromContext } = useChart();\n const chartConfig = config || configFromContext;\n\n const tooltipLabel = React.useMemo(() => {\n if (hideLabel || !payload || !payload.length) {\n return null\n }\n\n const [item] = payload\n const key = `${labelKey || item.dataKey || item.name || 'value'}`\n const itemConfig = getPayloadConfigFromPayload(chartConfig, item, key)\n const value =\n !labelKey && typeof label === \"string\"\n ? chartConfig[label as keyof typeof chartConfig]?.label || label\n : itemConfig?.label\n\n if (labelFormatter) {\n return (\n <div className={cn(\"font-medium\")}>\n {labelFormatter(value, payload)}\n </div>\n )\n }\n\n if (!value) {\n return null\n }\n\n return <div className={cn(\"font-medium\")}>{value}</div>\n }, [\n label,\n labelFormatter,\n payload,\n hideLabel,\n labelKey,\n chartConfig,\n ])\n\n if (!active || !payload?.length) {\n return null;\n }\n\n const nestLabel = payload.length === 1 && indicator !== \"dot\"\n\n return (\n <div\n ref={ref}\n className={cn(\n 'grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] px-2.5 py-1.5 text-xs shadow-xl transition-all ease-in-out animate-in fade-in-0 zoom-in-95',\n className\n )}\n >\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(chartConfig, item, key)\n const indicatorColor = colorToCssVariable(\n item.payload.fill || item.color\n )\n\n return (\n <div\n key={item.dataKey || index}\n className={cn(\n \"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground\",\n indicator === \"dot\" && \"items-center\"\n )}\n >\n {indicator && !hideIndicator && (\n <div\n className={cn(\n \"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]\",\n {\n \"h-2.5 w-2.5\": indicator === \"dot\",\n \"w-1\": indicator === \"line\",\n \"w-0 border-[1.5px] border-dashed bg-transparent\":\n indicator === \"dashed\",\n \"my-0.5\": nestLabel && indicator === \"dashed\",\n }\n )}\n style={\n {\n \"--color-bg\": indicatorColor,\n \"--color-border\": indicatorColor,\n } as React.CSSProperties\n }\n />\n )}\n <div\n className={cn(\n \"flex flex-1 justify-between leading-none\",\n nestLabel ? \"items-end\" : \"items-center\"\n )}\n >\n <div className=\"grid gap-1.5\">\n {nestLabel ? tooltipLabel : null}\n <span className=\"text-[var(--color-text-secondary)]\">\n {itemConfig?.label || item.name}\n </span>\n </div>\n {item.value && (\n <span className=\"font-mono font-medium tabular-nums text-[var(--color-text-primary)]\">\n {item.value.toLocaleString()}\n </span>\n )}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n );\n});\nChartTooltipContent.displayName = 'ChartTooltipContent';\n\n// -- Legend --\n\nconst ChartLegend = Legend;\n\nconst ChartLegendContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n hideIcon?: boolean;\n nameKey?: string;\n verticalAlign?: 'top' | 'bottom' | 'middle';\n payload?: any[];\n }\n>(({ className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey }, ref) => {\n const { config } = useChart();\n\n if (!payload?.length) {\n return null;\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex items-center justify-center gap-4',\n verticalAlign === 'top' ? 'pb-3' : 'pt-3',\n className\n )}\n >\n {payload.map((item) => {\n const key = `${nameKey || item.dataKey || \"value\"}`\n const itemConfig = getPayloadConfigFromPayload(config, item, key)\n const indicatorColor = colorToCssVariable(item.color)\n\n return (\n <div\n key={item.value}\n className={cn(\n \"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground\"\n )}\n >\n {!hideIcon && (\n <div\n className=\"h-2 w-2 shrink-0 rounded-[2px]\"\n style={{ backgroundColor: indicatorColor }}\n />\n )}\n <span className=\"text-sm text-[var(--color-text-primary)]\">\n {itemConfig?.label || item.value}\n </span>\n </div>\n )\n })}\n </div>\n );\n});\nChartLegendContent.displayName = 'ChartLegendContent';\n\n// Helper to extract config\nfunction getPayloadConfigFromPayload(\n config: ChartConfig,\n payload: unknown,\n key: string\n) {\n if (typeof payload !== \"object\" || payload === null) {\n return undefined\n }\n\n const payloadPayload =\n \"payload\" in payload &&\n typeof payload.payload === \"object\" &&\n payload.payload !== null\n ? payload.payload\n : undefined\n\n let configLabelKey: string = key\n\n if (\n key in payload &&\n typeof payload[key as keyof typeof payload] === \"string\"\n ) {\n configLabelKey = payload[key as keyof typeof payload] as string\n } else if (\n payloadPayload &&\n key in payloadPayload &&\n typeof payloadPayload[key as keyof typeof payloadPayload] === \"string\"\n ) {\n configLabelKey = payloadPayload[\n key as keyof typeof payloadPayload\n ] as string\n }\n\n return configLabelKey in config\n ? config[configLabelKey]\n : config[key as keyof typeof config]\n}\n\nfunction colorToCssVariable(color: string | undefined): string {\n if (!color) return 'var(--color-primary)';\n // If it's a theme variable like `var(--color-...)` return it\n if (color.startsWith('var(--')) return color;\n // If we wanted to map theme keys to vars, we could do it here\n return color;\n}\n\nexport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n ChartLegend,\n ChartLegendContent,\n ChartStyle,\n};\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":"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","names":["index_exports","__export","ChartContainer","ChartLegend","ChartLegendContent","ChartStyle","ChartTooltip","ChartTooltipContent","__toCommonJS","React","import_recharts","import_clsx","import_tailwind_merge","cn","inputs","import_jsx_runtime","ChartContext","useChart","context","ChartContainer","id","className","children","config","props","ref","uniqueId","chartId","cn","ChartStyle","colorConfig","_","value","key","item","color","ChartTooltip","ChartTooltipContent","active","payload","indicator","hideLabel","hideIndicator","label","labelFormatter","nameKey","labelKey","configFromContext","chartConfig","tooltipLabel","itemConfig","getPayloadConfigFromPayload","nestLabel","index","indicatorColor","colorToCssVariable","ChartLegend","ChartLegendContent","hideIcon","verticalAlign","payloadPayload","configLabelKey","__reExport","index_exports"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,7 @@
1
+ import*as l from"react";import{ResponsiveContainer as $,Legend as S,Tooltip as _}from"recharts";import{clsx as E}from"clsx";import{twMerge as M}from"tailwind-merge";function c(...t){return M(E(t))}import{jsx as s,jsxs as u}from"react/jsx-runtime";var w=l.createContext(null);function P(){let t=l.useContext(w);if(!t)throw new Error("useChart must be used within a <ChartContainer />");return t}var j=l.forwardRef(({id:t,className:e,children:r,config:o,...n},d)=>{let f=l.useId(),i=`chart-${t||f.replace(/:/g,"")}`;return s(w.Provider,{value:{config:o},children:u("div",{"data-chart":i,ref:d,className:c("flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-[var(--color-text-secondary)] [&_.recharts-cartesian-grid_line]:stroke-[var(--color-border)]",e),...n,children:[s(H,{id:i,config:o}),s($,{children:r})]})})});j.displayName="ChartContainer";var H=({id:t,config:e})=>{let r=Object.entries(e).filter(([o,n])=>n.theme||n.color);return r.length?s("style",{dangerouslySetInnerHTML:{__html:`
2
+ [data-chart=${t}] {
3
+ ${r.map(([o,n])=>{let d=n.theme||n.color;return d?`--color-${o}: ${d};`:null}).join(`
4
+ `)}
5
+ }
6
+ `}}):null},F=_,I=l.forwardRef(({active:t,payload:e,className:r,indicator:o="dot",hideLabel:n=!1,hideIndicator:d=!1,label:f,labelFormatter:i,config:C,nameKey:v,labelKey:g},L)=>{let{config:T}=P(),m=C||T,R=l.useMemo(()=>{if(n||!e||!e.length)return null;let[a]=e,y=`${g||a.dataKey||a.name||"value"}`,x=b(m,a,y),p=!g&&typeof f=="string"?m[f]?.label||f:x?.label;return i?s("div",{className:c("font-medium"),children:i(p,e)}):p?s("div",{className:c("font-medium"),children:p}):null},[f,i,e,n,g,m]);if(!t||!e?.length)return null;let h=e.length===1&&o!=="dot";return u("div",{ref:L,className:c("grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] px-2.5 py-1.5 text-xs shadow-xl transition-all ease-in-out animate-in fade-in-0 zoom-in-95",r),children:[h?null:R,s("div",{className:"grid gap-1.5",children:e.map((a,y)=>{let x=`${v||a.name||a.dataKey||"value"}`,p=b(m,a,x),N=k(a.payload.fill||a.color);return u("div",{className:c("flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",o==="dot"&&"items-center"),children:[o&&!d&&s("div",{className:c("shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",{"h-2.5 w-2.5":o==="dot","w-1":o==="line","w-0 border-[1.5px] border-dashed bg-transparent":o==="dashed","my-0.5":h&&o==="dashed"}),style:{"--color-bg":N,"--color-border":N}}),u("div",{className:c("flex flex-1 justify-between leading-none",h?"items-end":"items-center"),children:[u("div",{className:"grid gap-1.5",children:[h?R:null,s("span",{className:"text-[var(--color-text-secondary)]",children:p?.label||a.name})]}),a.value&&s("span",{className:"font-mono font-medium tabular-nums text-[var(--color-text-primary)]",children:a.value.toLocaleString()})]})]},a.dataKey||y)})})]})});I.displayName="ChartTooltipContent";var O=S,K=l.forwardRef(({className:t,hideIcon:e=!1,payload:r,verticalAlign:o="bottom",nameKey:n},d)=>{let{config:f}=P();return r?.length?s("div",{ref:d,className:c("flex items-center justify-center gap-4",o==="top"?"pb-3":"pt-3",t),children:r.map(i=>{let C=`${n||i.dataKey||"value"}`,v=b(f,i,C),g=k(i.color);return u("div",{className:c("flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"),children:[!e&&s("div",{className:"h-2 w-2 shrink-0 rounded-[2px]",style:{backgroundColor:g}}),s("span",{className:"text-sm text-[var(--color-text-primary)]",children:v?.label||i.value})]},i.value)})}):null});K.displayName="ChartLegendContent";function b(t,e,r){if(typeof e!="object"||e===null)return;let o="payload"in e&&typeof e.payload=="object"&&e.payload!==null?e.payload:void 0,n=r;return r in e&&typeof e[r]=="string"?n=e[r]:o&&r in o&&typeof o[r]=="string"&&(n=o[r]),n in t?t[n]:t[r]}function k(t){return t?(t.startsWith("var(--"),t):"var(--color-primary)"}export*from"recharts";export{j as ChartContainer,O as ChartLegend,K as ChartLegendContent,H as ChartStyle,F as ChartTooltip,I as ChartTooltipContent};
7
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/chart.tsx","../src/lib/utils.ts","../src/index.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { ResponsiveContainer, Legend, Tooltip } from 'recharts';\nimport { cn } from '../lib/utils';\n\n// Format: { THEME_NAME: { cssVariable: string; value: string } }\nconst THEMES = {\n light: {\n '--color-chart-1': '12 76% 61%',\n '--color-chart-2': '173 58% 39%',\n '--color-chart-3': '197 37% 24%',\n '--color-chart-4': '43 74% 66%',\n '--color-chart-5': '27 87% 67%',\n },\n dark: {\n '--color-chart-1': '220 70% 50%',\n '--color-chart-2': '160 60% 45%',\n '--color-chart-3': '30 80% 55%',\n '--color-chart-4': '280 65% 60%',\n '--color-chart-5': '340 75% 55%',\n },\n} as const;\n\nexport type ChartConfig = {\n [k in string]: {\n label?: React.ReactNode;\n icon?: React.ComponentType;\n color?: string;\n theme?: Record<keyof typeof THEMES, string>;\n }\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\nconst ChartContainer = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n config: ChartConfig;\n children: React.ComponentProps<typeof ResponsiveContainer>['children'];\n }\n>(({ id, className, children, config, ...props }, ref) => {\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-chart={chartId}\n ref={ref}\n className={cn(\n \"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-[var(--color-text-secondary)] [&_.recharts-cartesian-grid_line]:stroke-[var(--color-border)]\",\n className\n )}\n {...props}\n >\n <ChartStyle id={chartId} config={config} />\n <ResponsiveContainer>\n {children}\n </ResponsiveContainer>\n </div>\n </ChartContext.Provider>\n );\n});\nChartContainer.displayName = 'ChartContainer';\n\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\n const colorConfig = Object.entries(config).filter(\n ([_, value]) => value.theme || value.color\n );\n\n if (!colorConfig.length) {\n return null;\n }\n\n return (\n <style dangerouslySetInnerHTML={{\n __html: `\n [data-chart=${id}] {\n ${colorConfig\n .map(([key, item]) => {\n const color = item.theme || item.color;\n return color ? `--color-${key}: ${color};` : null;\n })\n .join('\\n')}\n }\n `\n }} />\n );\n};\n\n// -- Tooltip --\n\nconst ChartTooltip = Tooltip;\n\nconst ChartTooltipContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n hideLabel?: boolean;\n hideIndicator?: boolean;\n indicator?: 'line' | 'dot' | 'dashed';\n nameKey?: string;\n labelKey?: string;\n active?: boolean;\n payload?: any[];\n label?: any;\n labelFormatter?: (label: any, payload: any[]) => React.ReactNode;\n config?: ChartConfig;\n }\n>(({ active, payload, className, indicator = 'dot', hideLabel = false, hideIndicator = false, label, labelFormatter, config, nameKey, labelKey }, ref) => {\n const { config: configFromContext } = useChart();\n const chartConfig = config || configFromContext;\n\n const tooltipLabel = React.useMemo(() => {\n if (hideLabel || !payload || !payload.length) {\n return null\n }\n\n const [item] = payload\n const key = `${labelKey || item.dataKey || item.name || 'value'}`\n const itemConfig = getPayloadConfigFromPayload(chartConfig, item, key)\n const value =\n !labelKey && typeof label === \"string\"\n ? chartConfig[label as keyof typeof chartConfig]?.label || label\n : itemConfig?.label\n\n if (labelFormatter) {\n return (\n <div className={cn(\"font-medium\")}>\n {labelFormatter(value, payload)}\n </div>\n )\n }\n\n if (!value) {\n return null\n }\n\n return <div className={cn(\"font-medium\")}>{value}</div>\n }, [\n label,\n labelFormatter,\n payload,\n hideLabel,\n labelKey,\n chartConfig,\n ])\n\n if (!active || !payload?.length) {\n return null;\n }\n\n const nestLabel = payload.length === 1 && indicator !== \"dot\"\n\n return (\n <div\n ref={ref}\n className={cn(\n 'grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] px-2.5 py-1.5 text-xs shadow-xl transition-all ease-in-out animate-in fade-in-0 zoom-in-95',\n className\n )}\n >\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(chartConfig, item, key)\n const indicatorColor = colorToCssVariable(\n item.payload.fill || item.color\n )\n\n return (\n <div\n key={item.dataKey || index}\n className={cn(\n \"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground\",\n indicator === \"dot\" && \"items-center\"\n )}\n >\n {indicator && !hideIndicator && (\n <div\n className={cn(\n \"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]\",\n {\n \"h-2.5 w-2.5\": indicator === \"dot\",\n \"w-1\": indicator === \"line\",\n \"w-0 border-[1.5px] border-dashed bg-transparent\":\n indicator === \"dashed\",\n \"my-0.5\": nestLabel && indicator === \"dashed\",\n }\n )}\n style={\n {\n \"--color-bg\": indicatorColor,\n \"--color-border\": indicatorColor,\n } as React.CSSProperties\n }\n />\n )}\n <div\n className={cn(\n \"flex flex-1 justify-between leading-none\",\n nestLabel ? \"items-end\" : \"items-center\"\n )}\n >\n <div className=\"grid gap-1.5\">\n {nestLabel ? tooltipLabel : null}\n <span className=\"text-[var(--color-text-secondary)]\">\n {itemConfig?.label || item.name}\n </span>\n </div>\n {item.value && (\n <span className=\"font-mono font-medium tabular-nums text-[var(--color-text-primary)]\">\n {item.value.toLocaleString()}\n </span>\n )}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n );\n});\nChartTooltipContent.displayName = 'ChartTooltipContent';\n\n// -- Legend --\n\nconst ChartLegend = Legend;\n\nconst ChartLegendContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentProps<'div'> & {\n hideIcon?: boolean;\n nameKey?: string;\n verticalAlign?: 'top' | 'bottom' | 'middle';\n payload?: any[];\n }\n>(({ className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey }, ref) => {\n const { config } = useChart();\n\n if (!payload?.length) {\n return null;\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex items-center justify-center gap-4',\n verticalAlign === 'top' ? 'pb-3' : 'pt-3',\n className\n )}\n >\n {payload.map((item) => {\n const key = `${nameKey || item.dataKey || \"value\"}`\n const itemConfig = getPayloadConfigFromPayload(config, item, key)\n const indicatorColor = colorToCssVariable(item.color)\n\n return (\n <div\n key={item.value}\n className={cn(\n \"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground\"\n )}\n >\n {!hideIcon && (\n <div\n className=\"h-2 w-2 shrink-0 rounded-[2px]\"\n style={{ backgroundColor: indicatorColor }}\n />\n )}\n <span className=\"text-sm text-[var(--color-text-primary)]\">\n {itemConfig?.label || item.value}\n </span>\n </div>\n )\n })}\n </div>\n );\n});\nChartLegendContent.displayName = 'ChartLegendContent';\n\n// Helper to extract config\nfunction getPayloadConfigFromPayload(\n config: ChartConfig,\n payload: unknown,\n key: string\n) {\n if (typeof payload !== \"object\" || payload === null) {\n return undefined\n }\n\n const payloadPayload =\n \"payload\" in payload &&\n typeof payload.payload === \"object\" &&\n payload.payload !== null\n ? payload.payload\n : undefined\n\n let configLabelKey: string = key\n\n if (\n key in payload &&\n typeof payload[key as keyof typeof payload] === \"string\"\n ) {\n configLabelKey = payload[key as keyof typeof payload] as string\n } else if (\n payloadPayload &&\n key in payloadPayload &&\n typeof payloadPayload[key as keyof typeof payloadPayload] === \"string\"\n ) {\n configLabelKey = payloadPayload[\n key as keyof typeof payloadPayload\n ] as string\n }\n\n return configLabelKey in config\n ? config[configLabelKey]\n : config[key as keyof typeof config]\n}\n\nfunction colorToCssVariable(color: string | undefined): string {\n if (!color) return 'var(--color-primary)';\n // If it's a theme variable like `var(--color-...)` return it\n if (color.startsWith('var(--')) return color;\n // If we wanted to map theme keys to vars, we could do it here\n return color;\n}\n\nexport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n ChartLegend,\n ChartLegendContent,\n ChartStyle,\n};\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","export * from './components/chart';\nexport * from 'recharts';\n\n// Override specific recharts exports if we wrapped them, \n// otherwise we just export the primitives and let usage include regular recharts components.\n"],"mappings":"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","names":["React","ResponsiveContainer","Legend","Tooltip","clsx","twMerge","cn","inputs","jsx","jsxs","ChartContext","useChart","context","ChartContainer","id","className","children","config","props","ref","uniqueId","chartId","jsx","jsxs","cn","ChartStyle","ResponsiveContainer","colorConfig","_","value","key","item","color","ChartTooltip","Tooltip","ChartTooltipContent","active","payload","indicator","hideLabel","hideIndicator","label","labelFormatter","nameKey","labelKey","configFromContext","chartConfig","tooltipLabel","itemConfig","getPayloadConfigFromPayload","nestLabel","index","indicatorColor","colorToCssVariable","ChartLegend","Legend","ChartLegendContent","hideIcon","verticalAlign","payloadPayload","configLabelKey"]}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@thesage/charts",
3
+ "version": "0.1.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Chart components for Sage UI",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js"
16
+ }
17
+ },
18
+ "peerDependencies": {
19
+ "react": ">=18",
20
+ "recharts": "^2.12.0"
21
+ },
22
+ "devDependencies": {
23
+ "@types/react": "^19.0.0",
24
+ "tsup": "^8.0.0",
25
+ "typescript": "^5.0.0",
26
+ "@thesage/config": "0.0.1"
27
+ },
28
+ "dependencies": {
29
+ "clsx": "^2.1.1",
30
+ "tailwind-merge": "^3.4.0"
31
+ },
32
+ "scripts": {
33
+ "build": "tsup src/index.ts --format cjs,esm --dts",
34
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
35
+ "lint": "eslint src/"
36
+ }
37
+ }
@@ -0,0 +1,352 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { ResponsiveContainer, Legend, Tooltip } from 'recharts';
5
+ import { cn } from '../lib/utils';
6
+
7
+ // Format: { THEME_NAME: { cssVariable: string; value: string } }
8
+ const THEMES = {
9
+ light: {
10
+ '--color-chart-1': '12 76% 61%',
11
+ '--color-chart-2': '173 58% 39%',
12
+ '--color-chart-3': '197 37% 24%',
13
+ '--color-chart-4': '43 74% 66%',
14
+ '--color-chart-5': '27 87% 67%',
15
+ },
16
+ dark: {
17
+ '--color-chart-1': '220 70% 50%',
18
+ '--color-chart-2': '160 60% 45%',
19
+ '--color-chart-3': '30 80% 55%',
20
+ '--color-chart-4': '280 65% 60%',
21
+ '--color-chart-5': '340 75% 55%',
22
+ },
23
+ } as const;
24
+
25
+ export type ChartConfig = {
26
+ [k in string]: {
27
+ label?: React.ReactNode;
28
+ icon?: React.ComponentType;
29
+ color?: string;
30
+ theme?: Record<keyof typeof THEMES, string>;
31
+ }
32
+ };
33
+
34
+ type ChartContextProps = {
35
+ config: ChartConfig;
36
+ };
37
+
38
+ const ChartContext = React.createContext<ChartContextProps | null>(null);
39
+
40
+ function useChart() {
41
+ const context = React.useContext(ChartContext);
42
+
43
+ if (!context) {
44
+ throw new Error('useChart must be used within a <ChartContainer />');
45
+ }
46
+
47
+ return context;
48
+ }
49
+
50
+ const ChartContainer = React.forwardRef<
51
+ HTMLDivElement,
52
+ React.ComponentProps<'div'> & {
53
+ config: ChartConfig;
54
+ children: React.ComponentProps<typeof ResponsiveContainer>['children'];
55
+ }
56
+ >(({ id, className, children, config, ...props }, ref) => {
57
+ const uniqueId = React.useId();
58
+ const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`;
59
+
60
+ return (
61
+ <ChartContext.Provider value={{ config }}>
62
+ <div
63
+ data-chart={chartId}
64
+ ref={ref}
65
+ className={cn(
66
+ "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-[var(--color-text-secondary)] [&_.recharts-cartesian-grid_line]:stroke-[var(--color-border)]",
67
+ className
68
+ )}
69
+ {...props}
70
+ >
71
+ <ChartStyle id={chartId} config={config} />
72
+ <ResponsiveContainer>
73
+ {children}
74
+ </ResponsiveContainer>
75
+ </div>
76
+ </ChartContext.Provider>
77
+ );
78
+ });
79
+ ChartContainer.displayName = 'ChartContainer';
80
+
81
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
82
+ const colorConfig = Object.entries(config).filter(
83
+ ([_, value]) => value.theme || value.color
84
+ );
85
+
86
+ if (!colorConfig.length) {
87
+ return null;
88
+ }
89
+
90
+ return (
91
+ <style dangerouslySetInnerHTML={{
92
+ __html: `
93
+ [data-chart=${id}] {
94
+ ${colorConfig
95
+ .map(([key, item]) => {
96
+ const color = item.theme || item.color;
97
+ return color ? `--color-${key}: ${color};` : null;
98
+ })
99
+ .join('\n')}
100
+ }
101
+ `
102
+ }} />
103
+ );
104
+ };
105
+
106
+ // -- Tooltip --
107
+
108
+ const ChartTooltip = Tooltip;
109
+
110
+ const ChartTooltipContent = React.forwardRef<
111
+ HTMLDivElement,
112
+ React.ComponentProps<'div'> & {
113
+ hideLabel?: boolean;
114
+ hideIndicator?: boolean;
115
+ indicator?: 'line' | 'dot' | 'dashed';
116
+ nameKey?: string;
117
+ labelKey?: string;
118
+ active?: boolean;
119
+ payload?: any[];
120
+ label?: any;
121
+ labelFormatter?: (label: any, payload: any[]) => React.ReactNode;
122
+ config?: ChartConfig;
123
+ }
124
+ >(({ active, payload, className, indicator = 'dot', hideLabel = false, hideIndicator = false, label, labelFormatter, config, nameKey, labelKey }, ref) => {
125
+ const { config: configFromContext } = useChart();
126
+ const chartConfig = config || configFromContext;
127
+
128
+ const tooltipLabel = React.useMemo(() => {
129
+ if (hideLabel || !payload || !payload.length) {
130
+ return null
131
+ }
132
+
133
+ const [item] = payload
134
+ const key = `${labelKey || item.dataKey || item.name || 'value'}`
135
+ const itemConfig = getPayloadConfigFromPayload(chartConfig, item, key)
136
+ const value =
137
+ !labelKey && typeof label === "string"
138
+ ? chartConfig[label as keyof typeof chartConfig]?.label || label
139
+ : itemConfig?.label
140
+
141
+ if (labelFormatter) {
142
+ return (
143
+ <div className={cn("font-medium")}>
144
+ {labelFormatter(value, payload)}
145
+ </div>
146
+ )
147
+ }
148
+
149
+ if (!value) {
150
+ return null
151
+ }
152
+
153
+ return <div className={cn("font-medium")}>{value}</div>
154
+ }, [
155
+ label,
156
+ labelFormatter,
157
+ payload,
158
+ hideLabel,
159
+ labelKey,
160
+ chartConfig,
161
+ ])
162
+
163
+ if (!active || !payload?.length) {
164
+ return null;
165
+ }
166
+
167
+ const nestLabel = payload.length === 1 && indicator !== "dot"
168
+
169
+ return (
170
+ <div
171
+ ref={ref}
172
+ className={cn(
173
+ 'grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] px-2.5 py-1.5 text-xs shadow-xl transition-all ease-in-out animate-in fade-in-0 zoom-in-95',
174
+ className
175
+ )}
176
+ >
177
+ {!nestLabel ? tooltipLabel : null}
178
+ <div className="grid gap-1.5">
179
+ {payload.map((item, index) => {
180
+ const key = `${nameKey || item.name || item.dataKey || "value"}`
181
+ const itemConfig = getPayloadConfigFromPayload(chartConfig, item, key)
182
+ const indicatorColor = colorToCssVariable(
183
+ item.payload.fill || item.color
184
+ )
185
+
186
+ return (
187
+ <div
188
+ key={item.dataKey || index}
189
+ className={cn(
190
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
191
+ indicator === "dot" && "items-center"
192
+ )}
193
+ >
194
+ {indicator && !hideIndicator && (
195
+ <div
196
+ className={cn(
197
+ "shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
198
+ {
199
+ "h-2.5 w-2.5": indicator === "dot",
200
+ "w-1": indicator === "line",
201
+ "w-0 border-[1.5px] border-dashed bg-transparent":
202
+ indicator === "dashed",
203
+ "my-0.5": nestLabel && indicator === "dashed",
204
+ }
205
+ )}
206
+ style={
207
+ {
208
+ "--color-bg": indicatorColor,
209
+ "--color-border": indicatorColor,
210
+ } as React.CSSProperties
211
+ }
212
+ />
213
+ )}
214
+ <div
215
+ className={cn(
216
+ "flex flex-1 justify-between leading-none",
217
+ nestLabel ? "items-end" : "items-center"
218
+ )}
219
+ >
220
+ <div className="grid gap-1.5">
221
+ {nestLabel ? tooltipLabel : null}
222
+ <span className="text-[var(--color-text-secondary)]">
223
+ {itemConfig?.label || item.name}
224
+ </span>
225
+ </div>
226
+ {item.value && (
227
+ <span className="font-mono font-medium tabular-nums text-[var(--color-text-primary)]">
228
+ {item.value.toLocaleString()}
229
+ </span>
230
+ )}
231
+ </div>
232
+ </div>
233
+ )
234
+ })}
235
+ </div>
236
+ </div>
237
+ );
238
+ });
239
+ ChartTooltipContent.displayName = 'ChartTooltipContent';
240
+
241
+ // -- Legend --
242
+
243
+ const ChartLegend = Legend;
244
+
245
+ const ChartLegendContent = React.forwardRef<
246
+ HTMLDivElement,
247
+ React.ComponentProps<'div'> & {
248
+ hideIcon?: boolean;
249
+ nameKey?: string;
250
+ verticalAlign?: 'top' | 'bottom' | 'middle';
251
+ payload?: any[];
252
+ }
253
+ >(({ className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey }, ref) => {
254
+ const { config } = useChart();
255
+
256
+ if (!payload?.length) {
257
+ return null;
258
+ }
259
+
260
+ return (
261
+ <div
262
+ ref={ref}
263
+ className={cn(
264
+ 'flex items-center justify-center gap-4',
265
+ verticalAlign === 'top' ? 'pb-3' : 'pt-3',
266
+ className
267
+ )}
268
+ >
269
+ {payload.map((item) => {
270
+ const key = `${nameKey || item.dataKey || "value"}`
271
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
272
+ const indicatorColor = colorToCssVariable(item.color)
273
+
274
+ return (
275
+ <div
276
+ key={item.value}
277
+ className={cn(
278
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
279
+ )}
280
+ >
281
+ {!hideIcon && (
282
+ <div
283
+ className="h-2 w-2 shrink-0 rounded-[2px]"
284
+ style={{ backgroundColor: indicatorColor }}
285
+ />
286
+ )}
287
+ <span className="text-sm text-[var(--color-text-primary)]">
288
+ {itemConfig?.label || item.value}
289
+ </span>
290
+ </div>
291
+ )
292
+ })}
293
+ </div>
294
+ );
295
+ });
296
+ ChartLegendContent.displayName = 'ChartLegendContent';
297
+
298
+ // Helper to extract config
299
+ function getPayloadConfigFromPayload(
300
+ config: ChartConfig,
301
+ payload: unknown,
302
+ key: string
303
+ ) {
304
+ if (typeof payload !== "object" || payload === null) {
305
+ return undefined
306
+ }
307
+
308
+ const payloadPayload =
309
+ "payload" in payload &&
310
+ typeof payload.payload === "object" &&
311
+ payload.payload !== null
312
+ ? payload.payload
313
+ : undefined
314
+
315
+ let configLabelKey: string = key
316
+
317
+ if (
318
+ key in payload &&
319
+ typeof payload[key as keyof typeof payload] === "string"
320
+ ) {
321
+ configLabelKey = payload[key as keyof typeof payload] as string
322
+ } else if (
323
+ payloadPayload &&
324
+ key in payloadPayload &&
325
+ typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
326
+ ) {
327
+ configLabelKey = payloadPayload[
328
+ key as keyof typeof payloadPayload
329
+ ] as string
330
+ }
331
+
332
+ return configLabelKey in config
333
+ ? config[configLabelKey]
334
+ : config[key as keyof typeof config]
335
+ }
336
+
337
+ function colorToCssVariable(color: string | undefined): string {
338
+ if (!color) return 'var(--color-primary)';
339
+ // If it's a theme variable like `var(--color-...)` return it
340
+ if (color.startsWith('var(--')) return color;
341
+ // If we wanted to map theme keys to vars, we could do it here
342
+ return color;
343
+ }
344
+
345
+ export {
346
+ ChartContainer,
347
+ ChartTooltip,
348
+ ChartTooltipContent,
349
+ ChartLegend,
350
+ ChartLegendContent,
351
+ ChartStyle,
352
+ };
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './components/chart';
2
+ export * from 'recharts';
3
+
4
+ // Override specific recharts exports if we wrapped them,
5
+ // otherwise we just export the primitives and let usage include regular recharts components.
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "lib": [
6
+ "ES2020",
7
+ "DOM",
8
+ "DOM.Iterable"
9
+ ],
10
+ "jsx": "react-jsx",
11
+ "moduleResolution": "bundler",
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true,
15
+ "outDir": "./dist",
16
+ "rootDir": "./src",
17
+ "strict": true,
18
+ "esModuleInterop": true,
19
+ "skipLibCheck": true,
20
+ "forceConsistentCasingInFileNames": true,
21
+ "resolveJsonModule": true
22
+ },
23
+ "include": [
24
+ "src/**/*"
25
+ ],
26
+ "exclude": [
27
+ "node_modules",
28
+ "dist"
29
+ ]
30
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ clean: true,
8
+ minify: true,
9
+ sourcemap: true,
10
+ external: ['react', 'recharts'],
11
+ });