miku-charts
v0.0.9
Published
Librería de charts en React con arquitectura modular, temas configurables y tooltips extensibles. Diseñada para dashboards modernos con tipado estricto y componentes reutilizables.
Downloads
563
Readme
miku-charts
Librería de charts en React con arquitectura modular, temas configurables y tooltips extensibles. Diseñada para dashboards modernos con tipado estricto y componentes reutilizables.
Tabla De Contenidos
- Instalación
- Quick Start
- Conceptos Clave
- Modelo De Datos
- Props Comunes
- Labels Y Formato
- Tema Global
- Tooltips
- Paletas Y Colores
- Layout Y Responsividad
- Tailwind v4
- Charts Disponibles
- API Reference
- Ejemplos Por Chart
- Recetas
- FAQ
- Arquitectura Interna
- Playground
- Scripts
- Contribución
- Licencia
Instalación
pnpm add miku-chartsnpm install miku-chartsyarn add miku-chartsQuick Start
import { BarChart, ChartProvider } from "miku-charts"
const data = [
{ label: "Ene", value: 120 },
{ label: "Feb", value: 90 },
{ label: "Mar", value: 160 }
]
export function Dashboard() {
return (
<ChartProvider>
<BarChart data={data} height={320} />
</ChartProvider>
)
}Requisitos
- React 18+.
- Un contenedor con ancho visible.
heightosizedefinido en cada chart.
Conceptos Clave
- El ancho siempre es 100% del contenedor.
- El alto lo controla el usuario con
heightosize. - Los textos se controlan con
LabelConfig. - La estética se controla con el
ChartProvider. - Los tooltips se personalizan desde el tema o con plantillas.
Modelo De Datos
export type ChartDatum = {
value: number
label?: string
color?: string
meta?: Record<string, unknown>
}Props Comunes
heightdefine el alto del SVG en charts cartesianos (si no se pasa, toma el alto del contenedor).sizedefine el alto en charts polares (si no se pasa, toma el alto del contenedor).margincontrola espacio para ejes, labels y legend.labelscontrola el texto sobre puntos, barras y segmentos.xLabelsyyLabelsformatean labels del eje según el chart.colorspermite override de la paleta en charts por serie.classNamepermite usar Tailwind o clases utilitarias en el contenedor.
Labels Y Formato
LabelConfig controla visibilidad y formato para labels, valores y ejes.
type LabelConfig = {
show?: boolean
showLabel?: boolean
showValue?: boolean
formatter?: (value: number, label?: string) => string
fontSize?: number
rotate?: number | "auto"
maxChars?: number
}Ejemplo de labels globales:
<LineChart
data={data}
labels={{ show: true, showValue: true, showLabel: false, formatter: (v) => `${v}%` }}
xLabels={{ show: true, maxChars: 6 }}
/>Ejemplo con rotación automática:
<BarChart
data={data}
xLabels={{ show: true, rotate: "auto", maxChars: 10 }}
/>Tema Global
import { ChartProvider } from "miku-charts"
const theme = {
fontFamily: "'Inter', system-ui",
textColor: "#e5e7eb",
gridColor: "#ffffff22",
axisColor: "#ffffff66",
paletteName: "neon",
palettes: {
neon: ["#22d3ee", "#a78bfa", "#f472b6", "#facc15", "#4ade80"]
},
formatters: {
value: (v: number) => `${v.toLocaleString()}`,
axis: (v: number | string) => String(v),
tooltip: (v: unknown) => String(v)
}
}
<ChartProvider theme={theme}>
{/* charts */}
</ChartProvider>Tooltips
El tooltip se controla desde el tema con TooltipComponent. Plantillas incluidas:
ValueTooltipLabelValueTooltipDetailedTooltipSeriesTooltipCompactTooltipStackedTooltip
Ejemplo:
import { ChartProvider, SeriesTooltip } from "miku-charts"
<ChartProvider theme={{ TooltipComponent: SeriesTooltip }}>
{/* charts */}
</ChartProvider>Paletas Y Colores
paletteNameselecciona una paleta definida enpalettes.palettepuede definirse directamente para control fino.coloren cada dato puede sobreescribir la paleta.
<ChartProvider
theme={{
paletteName: "sunset",
palettes: {
sunset: ["#f97316", "#f59e0b", "#fbbf24", "#f472b6"]
}
}}
>
<BarChart data={data} />
</ChartProvider>Layout Y Responsividad
- El ancho es 100% del contenedor.
- El alto se toma de
height/sizeo del alto del contenedor. - Usa
marginpara que labels y legend no se corten.
<StackedAreaChart
data={data}
keys={["A", "B", "C"]}
height={360}
margin={{ top: 72, right: 32, bottom: 48, left: 56 }}
/>Ejemplo con alto definido por CSS:
<div style={{ height: 360 }}>
<BarChart data={data} />
</div>Tailwind CSS
Los charts exponen className en el contenedor para usar utilidades de Tailwind.
<BarChart
data={data}
height={320}
className="rounded-2xl border border-white/10 bg-white/5 p-4"
/>Tailwind v4
Los colores base se leen desde CSS variables (--foreground, --border, --muted-foreground, --popover, --chart-1..12).
Si no usas shadcn, define esos tokens o sobrescribe el tema con ChartProvider.
Ejemplo mínimo de tokens:
:root {
--foreground: #0f172a;
--border: #e2e8f0;
--muted-foreground: #64748b;
--popover: #ffffff;
--chart-1: #1f77b4;
--chart-2: #ff7f0e;
--chart-3: #2ca02c;
--chart-4: #d62728;
--chart-5: #9467bd;
}Tailwind v4 + Vite (playground)
Si usas Vite, la guía oficial recomienda el plugin:
npm install tailwindcss @tailwindcss/vite// vite.config.ts
import { defineConfig } from "vite"
import tailwindcss from "@tailwindcss/vite"
export default defineConfig({
plugins: [tailwindcss()],
})@import "tailwindcss";En este repo el playground ya está configurado así.
Charts Disponibles
BarChartChartDatum[]HorizontalBarChartChartDatum[]StackedBarChartdata: Record<string, number | string>[],keys: string[]StackedBarChartHorizontaldata: Record<string, number | string>[],keys: string[]StackedAreaChartdata: Record<string, number | string>[],keys: string[]ClusteredBarChartdata: Record<string, number | string>[],keys: string[]ClusteredBarChartHorizontaldata: Record<string, number | string>[],keys: string[]LineChartChartDatum[]AreaChartChartDatum[]LineChartMultiplecategories: string[],series: { label: string; values: number[] }[]ScatterChart{ x: number; y: number; label?: string }[]ScatterChartMulticlassseries: { label: string; points: { x: number; y: number; label?: string }[] }[]PieChartChartDatum[]DonutChartChartDatum[]RadarChartChartDatum[]TreemapChart{ label: string; value: number }[]HeatmapChart{ xLabels: string[]; yLabels: string[]; values: number[][] }DivergingBarChart{ label: string; value: number }[]PyramidChart{ label: string; left: number; right: number }[]VennDiagram{ label: string; value: number }[]
API Reference
ChartProvider
type ChartTheme = {
barColor: string
textColor: string
gridColor: string
axisColor: string
fontFamily: string
palette: string[]
palettes: Record<string, string[]>
paletteName?: string
fontSizes: {
axis: number
label: number
legend: number
tooltip: number
}
formatters?: {
value?: (value: number, label?: string) => string
label?: (label?: string) => string
axis?: (value: number | string) => string
tooltip?: (value: unknown, datum?: any) => string
}
TooltipComponent: React.ComponentType
}Ejemplo de uso:
<ChartProvider theme={{ paletteName: "miku" }}>
<BarChart data={data} height={320} />
</ChartProvider>BarChart / LineChart / AreaChart
type Props = {
data: ChartDatum[]
height?: number
labels?: LabelConfig
xLabels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}HorizontalBarChart
type Props = {
data: ChartDatum[]
height?: number
labels?: LabelConfig
yLabels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}StackedBarChart / StackedBarChartHorizontal / StackedAreaChart
type Props = {
data: Record<string, number | string>[]
keys: string[]
colors?: string[]
height?: number
labels?: StackedLabelConfig
xLabels?: LabelConfig
yLabels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}StackedLabelConfig
type StackedLabelConfig = LabelConfig & {
showTotals?: boolean
totalFormatter?: (total: number, label?: string) => string
segmentFormatter?: (value: number, info: { label?: string; series: string; total: number; index: number }) => string
}ClusteredBarChart / ClusteredBarChartHorizontal
type Props = {
data: Record<string, number | string>[]
keys: string[]
colors?: string[]
height?: number
labels?: LabelConfig
xLabels?: LabelConfig
yLabels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}LineChartMultiple
type Props = {
categories: string[]
series: { label: string; values: number[]; color?: string }[]
height?: number
labels?: LabelConfig
xLabels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}ScatterChart
type Props = {
data: { x: number; y: number; label?: string }[]
height?: number
labels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}ScatterChartMulticlass
type Props = {
series: { label: string; points: { x: number; y: number; label?: string }[]; color?: string }[]
height?: number
labels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}PieChart / DonutChart / RadarChart
type Props = {
data: ChartDatum[]
size?: number
labels?: LabelConfig
}TreemapChart
type Props = {
data: { label: string; value: number; color?: string }[]
height?: number
labels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}HeatmapChart
type Props = {
data: { xLabels: string[]; yLabels: string[]; values: number[][] }
height?: number
labels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}DivergingBarChart
type Props = {
data: { label: string; value: number; color?: string }[]
height?: number
labels?: LabelConfig
yLabels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}PyramidChart
type Props = {
data: { label: string; left: number; right: number }[]
height?: number
labels?: LabelConfig
yLabels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}VennDiagram
type Props = {
sets: { label: string; value: number; color?: string }[]
height?: number
labels?: LabelConfig
margin?: Partial<{ top: number; right: number; bottom: number; left: number }>
}Ejemplos Por Chart
BarChart
<BarChart
data={[
{ label: "Alpha", value: 40 },
{ label: "Beta", value: 55 },
{ label: "Gamma", value: 28 }
]}
height={300}
labels={{ show: true, showValue: true, showLabel: false }}
/>HorizontalBarChart
<HorizontalBarChart
data={[
{ label: "A", value: 32 },
{ label: "B", value: 18 },
{ label: "C", value: 44 }
]}
height={260}
labels={{ show: true }}
/>StackedBarChart
<StackedBarChart
data={[
{ label: "Q1", A: 30, B: 20, C: 12 },
{ label: "Q2", A: 28, B: 26, C: 16 },
{ label: "Q3", A: 45, B: 22, C: 18 }
]}
keys={["A", "B", "C"]}
height={320}
labels={{ show: true, showTotals: true }}
/>StackedBarChartHorizontal
<StackedBarChartHorizontal
data={[
{ label: "Norte", A: 20, B: 14, C: 10 },
{ label: "Sur", A: 18, B: 20, C: 12 }
]}
keys={["A", "B", "C"]}
height={260}
labels={{ show: true }}
/>StackedAreaChart
<StackedAreaChart
data={[
{ label: "Ene", A: 20, B: 15, C: 10 },
{ label: "Feb", A: 28, B: 18, C: 12 },
{ label: "Mar", A: 32, B: 24, C: 18 }
]}
keys={["A", "B", "C"]}
height={320}
/>ClusteredBarChart
<ClusteredBarChart
data={[
{ label: "2023", A: 30, B: 22, C: 18 },
{ label: "2024", A: 40, B: 28, C: 20 }
]}
keys={["A", "B", "C"]}
height={300}
labels={{ show: true }}
/>ClusteredBarChartHorizontal
<ClusteredBarChartHorizontal
data={[
{ label: "Team A", A: 12, B: 18, C: 10 },
{ label: "Team B", A: 16, B: 22, C: 14 }
]}
keys={["A", "B", "C"]}
height={260}
/>LineChart
<LineChart
data={[
{ label: "Ene", value: 120 },
{ label: "Feb", value: 90 },
{ label: "Mar", value: 160 }
]}
height={300}
labels={{ show: true }}
/>AreaChart
<AreaChart
data={[
{ label: "Ene", value: 120 },
{ label: "Feb", value: 90 },
{ label: "Mar", value: 160 }
]}
height={300}
/>LineChartMultiple
<LineChartMultiple
categories={["Jan", "Feb", "Mar", "Apr"]}
series={[
{ label: "Ventas", values: [12, 18, 15, 22] },
{ label: "Gasto", values: [8, 14, 10, 12] }
]}
height={320}
/>ScatterChart
<ScatterChart
data={[
{ x: 10, y: 40, label: "P1" },
{ x: 20, y: 25, label: "P2" },
{ x: 30, y: 50, label: "P3" }
]}
height={280}
/>ScatterChartMulticlass
<ScatterChartMulticlass
series={[
{ label: "Grupo A", points: [{ x: 10, y: 30 }, { x: 20, y: 18 }] },
{ label: "Grupo B", points: [{ x: 12, y: 40 }, { x: 24, y: 32 }] }
]}
height={280}
/>PieChart
<PieChart
data={[
{ label: "Web", value: 40 },
{ label: "Mobile", value: 35 },
{ label: "Retail", value: 25 }
]}
size={300}
labels={{ show: true }}
/>DonutChart
<DonutChart
data={[
{ label: "Free", value: 70 },
{ label: "Pro", value: 20 },
{ label: "Enterprise", value: 10 }
]}
size={300}
labels={{ show: true }}
/>RadarChart
<RadarChart
data={[
{ label: "Speed", value: 80 },
{ label: "Control", value: 60 },
{ label: "Quality", value: 90 }
]}
size={320}
labels={{ show: true }}
/>TreemapChart
<TreemapChart
data={[
{ label: "Product A", value: 120 },
{ label: "Product B", value: 80 },
{ label: "Product C", value: 60 }
]}
height={240}
labels={{ show: true }}
/>HeatmapChart
<HeatmapChart
data={{
xLabels: ["Mon", "Tue", "Wed", "Thu"],
yLabels: ["AM", "PM"],
values: [
[12, 18, 22, 15],
[8, 14, 19, 11]
]
}}
height={220}
labels={{ show: true }}
/>DivergingBarChart
<DivergingBarChart
data={[
{ label: "North", value: 40 },
{ label: "South", value: -25 },
{ label: "East", value: 18 },
{ label: "West", value: -30 }
]}
height={280}
labels={{ show: true }}
/>PyramidChart
<PyramidChart
data={[
{ label: "18-25", left: 20, right: 22 },
{ label: "26-35", left: 30, right: 28 },
{ label: "36-45", left: 25, right: 20 }
]}
height={300}
labels={{ show: true }}
/>VennDiagram
<VennDiagram
sets={[
{ label: "A", value: 60 },
{ label: "B", value: 40 },
{ label: "C", value: 30 }
]}
height={260}
labels={{ show: true }}
/>Recetas
Dashboard con múltiples charts
export function Dashboard() {
return (
<ChartProvider>
<div style={{ display: "grid", gridTemplateColumns: "repeat(2, minmax(0, 1fr))", gap: 24 }}>
<BarChart data={sales} height={280} />
<LineChart data={visits} height={280} />
<DonutChart data={channels} size={280} />
<ScatterChart data={quality} height={280} />
</div>
</ChartProvider>
)
}Comparación antes/después con Diverging
<DivergingBarChart
data={[
{ label: "Producto A", value: 12 },
{ label: "Producto B", value: -8 },
{ label: "Producto C", value: 20 },
{ label: "Producto D", value: -5 }
]}
labels={{ show: true }}
/>Piramide Poblacional
<PyramidChart
data={[
{ label: "18-25", left: 12, right: 14 },
{ label: "26-35", left: 22, right: 20 },
{ label: "36-45", left: 18, right: 16 }
]}
labels={{ show: true }}
yLabels={{ show: true }}
/>Series múltiples con color custom
<LineChartMultiple
categories={["Q1", "Q2", "Q3", "Q4"]}
series={[
{ label: "North", values: [12, 18, 15, 20], color: "#60a5fa" },
{ label: "South", values: [10, 14, 12, 16], color: "#f472b6" }
]}
labels={{ show: true }}
/>Stacked con totales y formato
<StackedBarChart
data={data}
keys={["A", "B", "C"]}
labels={{
show: true,
showTotals: true,
totalFormatter: (total) => `Total ${total}`,
segmentFormatter: (value, info) => `${info.series}: ${value}`
}}
/>FAQ
No se ve el chart
- Asegúrate de envolver con
ChartProvider. - Verifica que el contenedor tenga ancho visible.
- Define
height/sizeo un alto explícito en el contenedor.
Labels se cortan
- Aumenta
margin. - Reduce
fontSizeomaxChars. - Usa
rotate: "auto"enxLabels.
El tooltip no aparece
- Revisa que el chart esté dentro de
ChartProvider. - Verifica que no haya un contenedor con
overflow: hiddentapando el portal.
Tailwind v4 no aplica estilos
- Verifica que estés importando
@import "tailwindcss";en tu CSS. - Asegúrate de tener el plugin
@tailwindcss/vitesi usas Vite. - Define los tokens CSS (
--foreground,--border,--chart-1..12) o usaChartProvidercontheme.
Errores de imports en CSS
tw-animate-css: instalatw-animate-csso elimina el import.shadcn/tailwind.css: no es un paquete npm. Usa tus propios tokens o copia los de shadcn en un CSS local.
Arquitectura Interna
ChartRootmaneja escalas, layout, grid, ejes y leyendas en charts cartesianos.PolarChartRootse usa en charts radiales como pie, donut y radar.ChartCanvasRootpermite layouts customizados sin ejes ni grid por defecto.ChartContextdistribuyescales,innerWidth/Height,tooltip,legendy datos.- Primitivos desacoplados: bars, lines, dots, grids, labels, tooltips.
Playground
pnpm install
pnpm run devScripts
pnpm run devejecuta la lib y el playground en paralelopnpm run dev:libbuild en watchpnpm run dev:playgroundplayground con Vitepnpm run buildbuild de la libreríapnpm run testvitest
Contribución
pnpm run buildypnpm run testantes de abrir PR.- Mantén el tipado estricto activo en
tsconfig.json.
Licencia
Pendiente.
