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

@rezneed/rn-odontogram

v1.0.0

Published

Interactive dental chart (odontogram) for React Native — permanent and primary dentition, FDI tooth codes, built on react-native-svg.

Downloads

149

Readme

@rezneed/rn-odontogram

Interactive dental chart (odontogram) for React Native, drawn with react-native-svg. Supports the permanent (FDI 11–48) and primary (FDI 51–85) dentition, per-tooth selection, per-tooth condition colouring and read-only display.

It is the React Native counterpart of the web react-odontogram, rewritten so that everything the web version needs the DOM for — cropping the canvas, labelling teeth, primary quadrants — is part of the component instead.

┌─ upper arch ─────────────┐
│  18 17 … 11 │ 21 … 27 28 │   each arch is its own <Svg>, cropped to the
├─ lower arch ─────────────┤   teeth it actually draws, so nothing is
│  48 47 … 41 │ 31 … 37 38 │   scaled down by empty canvas
└──────────────────────────┘

Install

Published to npm as @rezneed/rn-odontogram:

yarn add @rezneed/rn-odontogram

react-native-svg is a peer dependency. Every React Native app here already has it; if not: yarn add react-native-svg.

The tarball is built on publish (prepacktsclib/), so lib/ is never committed. Bumping the app = change the version in package.json, yarn install.

Versioning

Plain semver, starting at 1.0.0 (the API below is what the app depends on):

| Change | Bump | Example | | ------------------------------------------------------------------------------- | --------------- | ------------------------------------------------- | | a prop is removed or renamed, a default changes, tooth codes come out different | major → 2.0.0 | making lowerQuadrants: 'fdi' the only behaviour | | a new prop or export, existing calls unaffected | minor → 1.1.0 | adding onToothLongPress | | a fix with the same API | patch → 1.0.1 | tap target off by a few px |

Release: bump version in package.jsonyarn test && yarn check → commit → publish a GitHub Release whose tag is v<version>. The Publish workflow (.github/workflows/publish.yml) checks the tag against package.json, builds and runs npm publish. Auth is npm trusted publishing (OIDC from GitHub Actions — no token stored anywhere); it is configured once on npmjs.com under the package's Settings → Trusted Publisher (Rezneed / rn-odontogram / publish.yml). A version that is already on npm is skipped, so re-running a release is safe.

Usage

import {useCallback, useState} from 'react';
import {Odontogram, ToothCode} from '@rezneed/rn-odontogram';

export const TeethPicker = ({width}: {width: number}) => {
  const [selected, setSelected] = useState<ToothCode[]>([]);

  const onToothPress = useCallback((code: ToothCode) => {
    setSelected(previous =>
      previous.includes(code)
        ? previous.filter(item => item !== code)
        : [...previous, code],
    );
  }, []);

  return (
    <Odontogram
      width={width}
      dentition="permanent"
      selected={selected}
      onToothPress={onToothPress}
      conditions={[
        {label: 'treated', teeth: ['16', '26'], fillColor: '#b37feb'},
      ]}
    />
  );
};

Selection is controlled — the component never keeps its own copy, so a selected change is reflected immediately (no remount tricks needed).

Read-only display, the way the customer plan tab uses it — no onToothPress, so no tap targets are rendered at all:

<Odontogram
  readOnly
  width={chartWidth}
  dentition={dentition}
  selected={plannedTeeth}
  archGap={14}
  colors={{selectedFill: '#F0EBFE', selectedOutline: '#8E59FF'}}
  lowerQuadrants="swapped"
/>

width is required — measure the container with onLayout and render the chart once the width is known. Tooth codes are strings ('11', '75'); an API that returns numbers needs .map(String).

Props

| Prop | Type | Default | Description | | ---------------- | ------------------------------ | ------------- | ----------------------------------------------------------------------------------------------- | | width | number | — | Required. Rendered width in px; each arch fills it and its height follows the aspect ratio. | | dentition | 'permanent' \| 'primary' | 'permanent' | 8 teeth per quadrant (11–48) or 5 (51–85). | | arch | 'both' \| 'upper' \| 'lower' | 'both' | Which arch(es) to draw. | | selected | ToothCode[] | [] | FDI codes painted as selected. | | conditions | IToothConditionGroup[] | — | Static per-tooth colouring, e.g. already-treated teeth. Selection wins over a condition. | | colors | Partial<IOdontogramColors> | see below | outline, selectedFill, selectedOutline, label. | | showLabels | boolean | true | Tooth number drawn on each tooth. | | labelFontSize | number | 10 | Label size in px (scaled into viewBox units internally). | | readOnly | boolean | false | Drops all tap targets. | | onToothPress | (code, tooth) => void | — | Called with the FDI code and the tooth's metadata. Without it the chart is not interactive. | | minTouchSize | number | 32 | Minimum tap target per tooth in px — small incisors get an enlarged hit box. | | archGap | number | 0 | Vertical gap between the two arches in px. | | lowerQuadrants | 'fdi' \| 'swapped' | 'fdi' | See below. | | style | StyleProp<ViewStyle> | — | Wrapper style. |

Default colours:

{outline: '#8a98be', selectedFill: '#c6ccf8', selectedOutline: '#3e5edc', label: '#1f2937'}

IToothConditionGroup:

{label?: string; teeth: ToothCode[]; fillColor: string; outlineColor?: string}

lowerQuadrants — the FDI caveat

The chart is drawn facing the patient, so the patient's right side is on the left of the screen: quadrant 1 top-left, quadrant 2 top-right, quadrant 4 bottom-left and quadrant 3 bottom-right. That is lowerQuadrants: 'fdi', the default and the anatomically correct mapping.

react-odontogram numbers the lower arch the other way round (quadrant 3 bottom-left), and rezneed-business-web stores codes produced by that chart. Pass lowerQuadrants="swapped" to reproduce it when the codes must line up with data already collected on the web.

Helpers

import {
  buildArchLayouts, // pure layout: arch viewBoxes + tooth placements
  dentitionOfCode, // '75' → 'primary'
  isPrimaryToothCode, // '75' → true
  QUADRANT_TEETH, // raw path data of one quadrant
  TOOTH_BOUNDS, // generated per-tooth bounding boxes
} from '@rezneed/rn-odontogram';

buildArchLayouts is what the component renders from — useful for tests or a custom renderer.

Development

yarn install
yarn test        # pure layout/geometry tests
yarn check       # tsc --noEmit
yarn build       # → lib/
yarn geometry    # regenerate src/data/teeth.geometry.ts from the path data
node scripts/preview.mjs   # after build: writes preview/*.svg to eyeball geometry

src/data/teeth.geometry.ts is generated — the bounding box of every tooth is computed from its path data at build time, which is what lets the component crop its viewBox and place labels without measuring rendered nodes (React Native has no getBBox).

Attribution

The SVG tooth path data in src/data/teeth.paths.ts is ported from react-odontogram v0.5.6, MIT licensed, © biomathcode. Everything else is an original implementation. See LICENSE for both notices.