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

@chipmobilesdk/rn-chart

v0.1.1

Published

Domain-agnostic charts for ChipMobileSdk-family React Native apps.

Readme

@chipmobilesdk/rn-chart

Domain-agnostic charts for ChipMobileSdk-family React Native apps.

License: UNLICENSED. Published publicly for use by the owner's applications; no open-source license is granted.

  • Version: 0.1.0
  • Entrypoint: @chipmobilesdk/rn-chart

One datasource contract spans five chart families. The package knows nothing about nutrition, finance, health, or productivity — you hand it aggregated, normalised data and it draws it.

What it does not do

Worth stating up front, because these are deliberate:

  • No insight or narrative surface. The package draws charts. Render your own explanatory text above or below a chart; it imposes no outer margin that would fight your layout.
  • No data fetching, no database access, no AI calls, no network of any kind. Everything arrives as props.
  • No aggregation. Your domain layer decides what the numbers mean.
  • No navigation. Interactions call back; what happens next is yours.

Install

npm install @chipmobilesdk/rn-chart react-native-svg
cd ios && pod install

react-native-svg is a required peer. There is no degraded no-SVG mode.

No permissions, entitlements, Info.plist usage strings, or Android manifest changes are needed. Note that this package's no-permission chart state is an app-level data-access concept, not an operating-system permission.

Compatibility

| | Supported | |---|---| | React | 19.2+ | | React Native | 0.85+ | | react-native-svg | 15.15+ | | Android | minSdkVersion 24, targetSdkVersion 36 | | iOS | 15.1+ |

Quick start

import { BarChart, known, unknown, type ChartDatasource } from '@chipmobilesdk/rn-chart';

const datasource: ChartDatasource = {
  positionKind: 'category',
  series: [{
    id: 'weekly',
    label: 'Weekly total',
    points: [
      { id: 'mon', position: { kind: 'category', category: 'Mon' }, value: known(12) },
      { id: 'tue', position: { kind: 'category', category: 'Tue' }, value: known(0) },
      { id: 'wed', position: { kind: 'category', category: 'Wed' }, value: unknown() },
    ],
  }],
};

export function Example() {
  return <BarChart datasource={datasource} height={220} title="This week" />;
}

Monday draws a bar. Tuesday draws a zero-height bar that reads as a real zero. Wednesday draws nothing and is marked as a gap — never a zero.

Keep your datasource referentially stable. Hold it in state or a useMemo. Rebuilding the object inline on every render defeats the memoization the package relies on, and that is not something a library can fix for you.

Value semantics

The most important part of the contract. Four classes, and only one carries a number:

known(42)          // a real observation, including known(0)
unknown()          // we do not know
notApplicable()    // does not apply here
withheld()         // hidden: permission, or not enough data

There is no value property on the three non-value cases, so value ?? 0 cannot compile. That is the point — turning a gap into a zero is the single most damaging thing a charting library can do to someone's data.

Consequences you can rely on:

  • An unknown value is never rendered as zero and never interpolated across. In a line chart the gap ends the subpath, so there is physically no segment to bridge it.
  • notApplicable and withheld are excluded from totals, and any total that excluded something is reported as incomplete.
  • A withheld value never appears in a rendering, a label, an accessible summary, or an interaction callback.
  • Each non-value class renders as its own texture, not a colour difference, so they stay distinguishable in greyscale.

The datasource contract

Every point shares one envelope — identity, value, optional unit and format hint, opaque metadata — and only its position varies:

{ kind: 'category', category: 'Mon' }
{ kind: 'instant', at: 1767225600000 }        // epoch ms, UTC
{ kind: 'matrix', row: 'week-1', column: 'Mon' }

Which families accept which:

| Family | category | instant | matrix | |---|:---:|:---:|:---:| | ProgressChart | ✓ | | | | DistributionChart | ✓ | | | | BarChart | ✓ | ✓ | | | TimeSeriesChart | | ✓ | | | HeatmapChart | | | ✓ |

Bar accepting both is what makes swapping a time-series chart for a bar chart free — same datasource, different component. Any other pairing is a validation error, not a rendering guess.

Time is epoch milliseconds and carries no timezone. All date wording comes from your formatters.

States

Seven, and the package derives the two that only the data can determine:

| Status | Who decides | |---|---| | empty, partial | derived from your datasource | | loading, stale, noPermission, error | you declare via status |

Precedence: noPermission > error > loading > empty > stale > partial > ready. noPermission outranks everything so restricted values cannot slip through another state.

Supply your own copy — the package's built-in wording is a terse placeholder, not product voice:

<BarChart
  datasource={ds}
  status="loading"
  stateContent={{
    empty: <Text>Log your first meal to see this chart</Text>,
    loading: <Spinner />,
  }}
/>

Failure containment

Each chart contains its own render exceptions. One bad datasource collapses one chart, never the dashboard around it:

<BarChart datasource={ds} chartId="calories" onFailure={report => crashReporter.log(report)} />

Failure reports carry the chart identity, family, and a catalogue message — never data values or series labels. This matters if you chart health or financial data, because a report is the easiest accidental path from a chart into a third-party crash reporting service.

Interaction

Uncontrolled by default. Supply a selection value (including null) to take ownership; the same callbacks fire either way.

// Uncontrolled: the chart tracks its own selection.
<BarChart datasource={ds} onSelectionChange={(ref, event) => log(event)} />

// Controlled: you are the source of truth.
<BarChart
  datasource={ds}
  selection={selection}
  onSelectionChange={setSelectionFromRef}
  onSelectionUnresolvable={ref => setSelection(null)}
/>

Every payload carries the point id, series id, value, position, and whatever metadata you attached. The package never navigates, fetches, or mutates.

Legends can also toggle series visibility. The state is uncontrolled unless you supply hiddenSeriesIds:

<BarChart
  datasource={ds}
  seriesToggleEnabled
  hiddenSeriesIds={hiddenSeriesIds}
  onVisibilityChange={event => updateHiddenSeries(event.seriesId)}
/>

Pan, pinch-zoom, and brush-to-select are out of scope. range on TimeSeriesChart is a window you supply, not one the user draws.

Theming

The package defines its own ChartTheme value type and takes no dependency on @chipmobilesdk/rn-theme or react-native-unistyles. Any design system can satisfy it:

import { ChartThemeProvider, defaultChartTheme } from '@chipmobilesdk/rn-chart';

const chartTheme = {
  ...defaultChartTheme(scheme),
  palette: myTokens.dataviz,
  surface: myTokens.surface,
};

<ChartThemeProvider theme={chartTheme}>{children}</ChartThemeProvider>

Resolution order: explicit theme prop → provider context → built-in default keyed on useColorScheme(). With no configuration at all, charts still render correctly in light and dark.

Meaning never rides on colour alone: series carry dash patterns as well as colours, and non-value classes use textures.

Formatting

<TimeSeriesChart
  datasource={ds}
  formatters={{
    value: v => (v.kind === 'known' ? intl.number(v.value) : '—'),
    axisLabel: p => ('at' in p ? intl.date(p.at) : String(p)),
  }}
/>

Your output is used verbatim. With no formatter, a documented locale-neutral default applies — the package never infers or converts a business unit. A formatter that throws degrades to the default for that one label and does not crash the screen.

Accessibility

Each chart is a single accessible element with a composed summary: what it is, what it shows, where the extremes are, what any target says. With selection enabled the root becomes adjustable, so increment and decrement walk the data points — the same access touch gives.

Non-ready charts announce their state rather than reading out figures they are not showing. Accessibility props you supply are never overridden.

Axis labels are thinned to fit rather than overlapped, and scale with the system text size up to 1.6×; beyond that the growth is capped so the plot area survives.

Dataset budgets

| Family | Budget | |---|---| | Time series | 5 series × 500 points | | Bar | 5 series × 60 categories | | Distribution | 12 segments | | Progress | 8 metrics | | Heatmap | 1,000 cells |

Over budget, a chart still renders and drops nothing. It warns once per chart in development builds, and never in production. Aggregating or downsampling above these sizes is your call — the package will not silently decide what data to discard.

Element count scales with series, not points: an at-budget time-series chart emits about six SVG elements, not 2,500.

Data behaviour (for App Privacy and Data Safety)

For consuming apps completing Apple App Privacy or Google Play Data Safety declarations:

  • The package holds the values and labels you pass it in memory only, for the lifetime of the rendered component.
  • It collects nothing, generates nothing, persists nothing, transmits nothing, and shares nothing with third parties.
  • It logs no data point value and no series label in production builds, including inside failure reports.
  • It requests no permissions and reads no device identifiers.

This package introduces no data-collection declaration of its own. If your app sends charted data anywhere, that collection is yours to declare.

If you render your own narrative text near a chart — particularly text from an AI service or from users — moderation and content obligations are entirely yours. The package ships no free-text surface at all.

Public API

src/index.ts is the only entrypoint. Geometry, scales, layout maths, path builders, the chart shell, and the SVG adapter are private so they can change without a breaking release.

Stable: value semantics, Position, the datasource types, the five chart components and their base props, ChartStatus, the error types, interaction events.

The single entrypoint exports these public groups:

  • Components: BarChart, DistributionChart, HeatmapChart, ProgressChart, TimeSeriesChart, ChartLegend, ChartThemeProvider, useChartTheme, buildLegendEntries, and their props
  • Values and datasource: known, unknown, notApplicable, withheld, isKnown, isWithheld, sumKnown, position/series/datasource types, marker helpers, and format resolution helpers
  • State and validation: resolveStatus, drawsData, suppressesInteraction, STATUS_PRECEDENCE, DATASET_BUDGETS, checkBudget, error/failure types, and isChartError
  • Interaction: selection and series interaction types plus sameSelection
  • Theme and formatting: defaultChartTheme, resolveSeriesColor, default formatter helpers, NON_VALUE_TEXT, and public theme/formatter contracts
  • Accessibility: buildChartSummary, buildPointAnnouncement, and buildTotalAnnouncement

Experimental — may change in a minor: ChartTheme token set, LegendEntry, family-specific props (shape, grouping, buckets), and the DATASET_BUDGETS figures.

Reserved for a future additive minor: an insight presentation surface and composable chart primitives. Neither will change the datasource, state, or interaction contracts when it lands.

Contributing

The one architectural rule worth knowing: nothing under src/geometry/ may import React or react-native-svg. It is pure functions over plain data, enforced by an ESLint override and by geometryPurity.test.ts. That is what keeps the geometry testable without a renderer and the drawing substrate replaceable.

npm run lint
npm test
npm run typecheck:chart
npm run pack:chart
npm run validate:chart   # all of the above

The demo integration lives in src/screens/ChartDemoScreen.tsx.