npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zuilib/charts

v0.5.0

Published

ZUI — enterprise analytics charts on Recharts: a serializable chart spec, styled primitives, and cross-filtering that links charts to data tables

Readme

@zuilib/charts

Enterprise analytics charts on Recharts, styled only through ZUI tokens: a serializable chart spec for runtime chart builders, styled primitives for hand-written composition, and cross-filtering that links charts to each other and to @zuilib/data-grid — without a hard dependency on it.

Install

pnpm add @zuilib/charts

React and React DOM are the required peers. Recharts, the ZUI primitives and tokens install transitively. Install recharts yourself only when your own code imports it for hand-written composition.

For a Tailwind v4 host, load the component and chart source entries once:

@import "tailwindcss";
@import "@zuilib/primitives/tailwind.css";
@import "@zuilib/charts/tailwind.css";

Usage

import Chart from '@zuilib/charts'

// Plain JSON: store it, send it from a server, let users build it.
const spec = {
  version: 1,
  type: 'bar',
  title: 'Revenue by region',
  xKey: 'region',
  series: [{field: 'revenue', label: 'Revenue', format: 'currency:USD'}],
  yAxis: {format: 'compact'},
}

<Chart spec={spec} rows={rows} />

Component API

Chart — @zuilib/charts

| Prop | Type | Default | |------|------|---------| | spec | ChartSpec | required — the serializable chart description | | rows | ChartRow[] | required — the rows behind the chart | | registry | ChartRegistry | built-ins — createChartRegistry(defaultChartTypes, yourDefs) adds or overrides types without forking the component | | formats | Record<string, FormatterFn \| FormatterFactory> | — custom formatter tokens the spec may name (functions stay out of the spec) | | locale | string | user's locale — BCP 47 tag for formatted values | | width / height | number | responsive — fixed pixel size for tests and SSR | | aspect | number | 16/9 — responsive width/height ratio when height is left out; the chart never gets shorter than 200px | | loading | boolean | false — renders a skeleton instead of the chart | | error | ReactNode | — renders an error state instead of the chart | | emptyState | ReactNode | the noData label — renders when rows is empty | | hiddenSeries / defaultHiddenSeries / onHiddenSeriesChange | string[], string[], (fields: string[]) => void | — series fields hidden by the legend; controlled when hiddenSeries is passed, otherwise kept internally from defaultHiddenSeries | | onMarkClick | (event: ChartMarkEvent) => void | — every mark click, whether or not a CrossFilterProvider is present | | labels | Partial<ChartLabels> | English — every built-in string | | animate | boolean | true unless the user prefers reduced motion | | ariaLabel | string | the spec's title — accessible name of the figure | | className | string | merged onto the container |

Sizing

A chart fills its container. Leave width and height out and the frame measures itself: the height follows aspect (16/9) with a 200px floor so a phone-width chart keeps a readable plot; pass height to fix the height and keep the width fluid; pass both for a fixed size (tests, SSR). The frame is a CSS size container (@container, min-w-0), so it never holds a flex or grid parent open at the width of a previous render — put it in any column without a min-w-0 of your own. Under 384px the value axis sizes to its labels and the category axis keeps only its end ticks; the legend wraps and, on touch pointers, its buttons grow to 44px hit areas. Desktop rendering does not change.

Entry points

@zuilib/charts (or ./chart) is the config-driven renderer: ten chart types (line, area, bar, pie/donut, scatter, composed, radar, radial-bar, funnel, treemap) from one discriminated ChartSpec, with loading, error and empty states, a controlled hiddenSeries legend, and onMarkClick. Formats are named tokens ('currency:USD', 'compact', 'percent', 'date:short') resolved through ./format; custom formatter functions arrive via the formats prop so the spec stays JSON.

./registry is the open chart-type registry <Chart> dispatches through. Every type is a ChartTypeDef — renderer, cross-filter fields, and a complete JSON Schema of its spec variant — and createChartRegistry(defaultChartTypes, yourDefs) merges defs last-wins by type, so an app adds or overrides a chart type without forking the package:

import { createChartRegistry, defaultChartTypes, defineChartType, chartTypeSchema } from '@zuilib/charts/registry'

const registry = createChartRegistry(defaultChartTypes, [
  defineChartType<GaugeChartSpec>({
    type: 'gauge',
    family: 'named',
    render: GaugeRenderer, // receives RendererProps<GaugeChartSpec> from @zuilib/charts/authoring
    crossFilterField: (spec) => spec.nameKey,
    schema: chartTypeSchema('gauge', {
      nameKey: { type: 'string' },
      valueKey: { type: 'string' },
    }, ['nameKey', 'valueKey']),
  }),
])

<Chart spec={gaugeSpec} rows={rows} registry={registry} />

Custom specs type as CustomChartSpec (type plus the shared options and whatever the def's schema declares); built-in specs stay the closed ChartSpec union, so the escape hatch never loosens their checking. chartSpecJsonSchema(registry?) emits the whole ChartSpec JSON Schema (draft 2020-12, per-type if/then conditionals from the defs' complete fragments) for validation and structured generation — one source, so the schema can't drift from what renders.

./authoring is the custom-chart authoring surface: RendererProps (what a registered renderer receives) and the mark-interaction helpers (reportMarkClick, activeCategoryValues, markDimOpacity, MarkInteraction) that keep an app-registered chart type's clicks and dimming consistent with the built-ins.

./chart-frame, ./chart-tooltip, ./chart-legend and ./chart-defaults are the primitives for hand-written Recharts composition: ChartFrame owns the series-color CSS variables (fill={seriesColorVar('revenue')}) and the states; ChartTooltipPanel and ChartLegendList render on popover tokens via Recharts' Tooltip/Legend content prop, the legend as real buttons (click isolates, shift-click toggles, aria-pressed).

./cross-filter is the shared filter/highlight state (CrossFilterProvider, useCrossFilter) with the same controlled/uncontrolled whole-state contract as the data grid; ./interop is four pure converters (toColumnFilters, fromColumnFilters, toHighlight, applyFilters) that wire it to a data grid's columnFilters and row selection structurally, with zero imports.

Theming

Series colors are the --chart-1 … --chart-8 tokens — a categorical palette validated for color-vision-deficiency separation in both modes. Slots are assigned in fixed declaration order and never cycled. A brand may override --chart-1 with its primary hue; overriding more slots requires re-validating the order. Grid lines, ticks, tooltips and states read the same semantic tokens as every other ZUI package.

Localisation

Every built-in string is overridable through the labels prop (ChartLabels), and every formatted value honors the locale prop. Mark entrance animation follows prefers-reduced-motion (or the animate prop).