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

historical-timeline-react

v0.1.0

Published

Private React vertical timeline component with discrete zoom from `century` down to `day`.

Readme

historical-timeline-react

Private React vertical timeline component with discrete zoom from century down to day.

This repo currently contains:

  • the reusable timeline library
  • a local demo app used for development and iteration

Related repo:

  • consumer example app: https://github.com/yehaisong/timeline-react-consumer

Status

The library surface is being extracted for private publishing through GitHub Packages.

Install

npm install historical-timeline-react

Usage

Import the library stylesheet once:

import 'historical-timeline-react/styles.css';

Minimal usage:

import {
  VerticalTimeline,
  type TimelineEvent,
} from 'historical-timeline-react';

const events: TimelineEvent[] = [
  {
    id: 'moon-landing',
    title: 'Apollo 11 Moon Landing',
    start: '1969-07-20',
    importance: 10,
  },
];

export function Example() {
  return (
    <VerticalTimeline
      events={events}
      maxZoomUnit="century"
      minZoomUnit="day"
      initialZoomUnit="decade"
      height={800}
      unitHeight={100}
    />
  );
}

Event Date Fields

The component supports three separate date concerns:

  • start / end: semantic source-of-truth event dates
  • placementStart / placementEnd: optional exact dates used only for placement on the timeline
  • displayStart / displayEnd: optional strings used only for built-in date text in the detail panel and cluster list

This is useful when your source data is year-only, but you still want more precise placement on the rail.

Example:

const events: TimelineEvent[] = [
  {
    id: 'azusa-street',
    title: 'Azusa Street Revival',
    start: '1906',
    end: '1909',
    placementStart: '1906-04-09',
    placementEnd: '1909-01-01',
    displayStart: '1906',
    displayEnd: '1909',
  },
];

Demo Settings Template

The demo app loads its timeline behavior and appearance from:

  • src/data/timeline-settings.json

Sample alternate templates are included at:

  • src/data/timeline-settings-ocean.json
  • src/data/timeline-settings-ember.json

That JSON file is the template for:

  • zoom bounds
  • default zoom
  • unit height
  • detail mode
  • display options
  • theme options

The settings panel edits that same shape in memory, and Reset restores the values from the JSON file.

Public Config Surface

Behavior options:

type TimelineDisplayOptions = {
  showMiniMap?: boolean;
  showMajorTicks?: boolean;
  showMajorLabels?: boolean;
  showMinorTicks?: boolean;
  showMinorLabels?: boolean;
  miniMapWidth?: number;
  clusterLaneLimit?: number;
};

Theme options:

type TimelineTheme = {
  axisColor?: string;
  majorTickColor?: string;
  minorTickColor?: string;
  labelPillBg?: string;
  labelPillText?: string;
  eventCardBg?: string;
  eventCardText?: string;
  eventCardBorder?: string;
  eventCardHoverBg?: string;
  eventCardActiveBorder?: string;
  miniMapBg?: string;
  miniMapBorder?: string;
  miniMapTrackColor?: string;
  miniMapViewportBorder?: string;
  miniMapViewportBg?: string;
  miniMapDensityLow?: string;
  miniMapDensityHigh?: string;
  cardWidth?: number;
  cardMaxWidth?: number;
  stackOffset?: number;
  axisWidth?: number;
  axisOffset?: number;
  labelShift?: number;
};

Example:

<VerticalTimeline
  events={events}
  maxZoomUnit="century"
  minZoomUnit="year"
  initialZoomUnit="decade"
  unitHeight={120}
  display={{
    showMiniMap: true,
    showMajorTicks: true,
    showMajorLabels: true,
    showMinorTicks: false,
    showMinorLabels: false,
    miniMapWidth: 160,
  }}
  theme={{
    axisColor: '#111827',
    majorTickColor: '#374151',
    minorTickColor: '#94a3b8',
    labelPillBg: '#111827',
    labelPillText: '#f8fafc',
    cardMaxWidth: 240,
    stackOffset: 96,
  }}
/>

Handling Event Clicks And Detail Panels

The timeline supports both patterns:

  1. consumer-managed detail UI through onEventClick
  2. built-in detail UI through detailMode

Built-in detail options:

type TimelineDetailMode = 'none' | 'modal' | 'slide';

The component default is slide.

Example:

<VerticalTimeline
  events={events}
  detailMode="slide"
/>

If you want full control, use onEventClick to open your own detail UI, such as:

  • a side drawer
  • a modal
  • a bottom sheet
  • an inline detail panel

Consumer-managed example:

import { useState } from 'react';
import {
  VerticalTimeline,
  type NormalizedTimelineEvent,
  type TimelineEvent,
} from 'historical-timeline-react';

const events: TimelineEvent[] = [
  {
    id: 'apollo-11',
    title: 'Apollo 11 Moon Landing',
    start: '1969-07-20',
    description: 'First crewed lunar landing.',
  },
];

export function TimelineWithDetailPanel() {
  const [selectedEvent, setSelectedEvent] = useState<NormalizedTimelineEvent | null>(null);

  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) 320px', gap: 16 }}>
      <VerticalTimeline
        events={events}
        maxZoomUnit="century"
        minZoomUnit="day"
        initialZoomUnit="decade"
        height={800}
        unitHeight={100}
        onEventClick={setSelectedEvent}
      />

      {selectedEvent ? (
        <aside>
          <h2>{selectedEvent.title}</h2>
          <p>{selectedEvent.description}</p>
        </aside>
      ) : null}
    </div>
  );
}

Use the built-in detailMode when the default panel behavior is enough, and use onEventClick when your app needs a custom detail surface.

Scripts

  • npm run dev runs the local demo app
  • npm run build:demo builds the demo app to dist-demo
  • npm run build
  • npm run build:lib builds the library package to dist

Current Scope

Library code:

  • src/components
  • src/hooks
  • src/lib
  • src/styles/library.css
  • src/index.ts

Demo-only code:

  • src/App.tsx
  • src/main.tsx
  • src/styles/app.css
  • local sample data

Copyright

Copyright (c) 2026 Haisong Ye. Released under the MIT License.

Built with Codex GPT-5.4.