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

new-js-clock

v1.0.0

Published

A modern TypeScript clock library with countdown support - jQuery-free rewrite of JS-Clock

Readme

New JS Clock

A modern TypeScript rewrite of the classic JS-Clock library, featuring full type safety, no dependencies, and proper multi-instance support.

Test Coverage

Check out this project's demo here.

🚀 What's New in Version 1.0.0

  • 🔒 TypeScript: Full type safety with comprehensive interfaces
  • 🌐 E2E + Unit Test Suite: Deterministic Jest coverage plus Selenium E2E browser tests (including extended background-tab behavior validation)
  • 📦 Zero Dependencies: Pure vanilla JavaScript, no jQuery required
  • 🐛 Bug Fixes: Multi-instance support works correctly (main issue in v0.8)
  • ⚡ Modern API: Clean, intuitive API with proper instance methods
  • 🧪 Fully Tested: 162 deterministic Jest tests with 99.74% lines/99.02% statements/100% functions and 98.32% branch coverage
  • 🐳 Dockerized E2E Grid: Selenium Grid via selenium/standalone-all-browsers on port 4444, running headless Chrome/Firefox/Edge locally and in CI (pnpm run e2e:docker)
  • 📱 ES Modules: ES Module imports with tree-shaking support
  • 🌍 DST-Aware Timezones: IANA timezone support with automatic daylight saving time handling
  • ⏱️ Stopwatch Mode: New stopwatch that counts up from 00:00:00
  • 🏁 Lap & Split Times: Record lap times (delta) and split times (cumulative)
  • 📊 Best/Worst Lap: Built-in helpers to find best and worst lap times
  • 🎯 High-Resolution Timing: Lap deltas measured via performance.now() for sub-millisecond precision

📦 Installation

# npm
npm install new-js-clock

# pnpm
pnpm add new-js-clock

# yarn
yarn add new-js-clock

CDN (Script Tag)

For direct browser usage without a bundler:

<!-- Minified (recommended for production) -->
<script src="https://unpkg.com/new-js-clock/dist/new-js-clock.min.js"></script>

<!-- Or via jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/new-js-clock/dist/new-js-clock.min.js"></script>

<!-- Unminified (for debugging) -->
<script src="https://unpkg.com/new-js-clock/dist/new-js-clock.js"></script>

After loading, the library is available as NewJSClock:

var clock = NewJSClock.createClock(document.getElementById('clock'));

🛠️ Build & Development

# Build the project (includes TypeScript type checking)
pnpm run build

# Build ESM output and type declarations
pnpm run build:esm

# Build CommonJS bundle only
pnpm run build:cjs

# Build IIFE bundles only
pnpm run build:iife

# Watch mode for development
pnpm run dev

🧪 Testing

# Run tests
pnpm test

# Run tests with coverage
pnpm run test:coverage

# Run tests in watch mode
pnpm run test:watch

# Run end to end tests using dockerized Selenium Grid for Chrome, Firefox and Edge testing
pnpm run e2e:docker

🔍 Linting

# Run ESLint
pnpm lint

# Auto-fix linting issues
pnpm run lint:fix

Test Quality Snapshot: 162 passing Jest tests with 99.74% line coverage, 99.02% statement coverage, 98.32% branch coverage, and 100% function coverage. E2E Snapshot: Dockerized Selenium Grid using selenium/standalone-all-browsers on port 4444, executing headless browser runs for Chrome, Firefox, and Edge via pnpm run e2e:docker.

📖 Usage

Basic System Clock

import { createClock } from 'new-js-clock';

const clock = createClock(document.getElementById('clock'));

// Control the clock
clock.stopClock();    // Pause
clock.startClock();   // Resume
clock.toggleClock();  // Toggle

// Get current time
const currentTime = clock.getTime(); // "14:30:25"

// Clean up
clock.destroy();

CommonJS Usage

const { createClock } = require('new-js-clock');

const clock = createClock(document.getElementById('clock'));

Countdown Timer

const countdown = createClock(
  document.getElementById('timer'),
  '00:05:00',  // 5 minutes
  {
    countdown: true,
    callback: () => alert('Time is up!')
  }
);

High Precision (with Centiseconds)

const precision = createClock(
  document.getElementById('precision'),
  undefined,  // Use system time
  { showCenti: true }  // Show centiseconds
);

Custom Start Time

const custom = createClock(
  document.getElementById('custom'),
  '10:30:45'  // Start at this time
);

12-Hour Format with AM/PM

const clock12h = createClock(
  document.getElementById('clock12h'),
  undefined,  // Use system time
  { use12Hour: true }
);
// Display: "02:30:45 PM" for 14:30:45

Multiple Timezones

DST-Aware (Recommended):

// Using IANA timezone names - automatically handles DST!
const nyClock = createClock(
  document.getElementById('ny-time'),
  undefined,
  { timezone: 'America/New_York' }  // Adjusts for EST/EDT
);

const londonClock = createClock(
  document.getElementById('london-time'),
  undefined,
  { timezone: 'Europe/London' }  // Adjusts for GMT/BST
);

const tokyoClock = createClock(
  document.getElementById('tokyo-time'),
  undefined,
  { timezone: 'Asia/Tokyo' }
);

Static Offset (No DST):

// Using static offset - does NOT handle DST
const nyClock = createClock(
  document.getElementById('ny-time'),
  undefined,
  { timezoneOffset: -5 }  // Always UTC-5
);

const mumbaiClock = createClock(
  document.getElementById('mumbai-time'),
  undefined,
  { timezoneOffset: 5.5 }  // Supports half-hour offsets
);

Resetting a Countdown Timer

const countdown = createClock(
  document.getElementById('timer'),
  '00:05:00',
  { countdown: true }
);

// Reset to initial time and restart - no need to destroy/recreate!
countdown.reset();

Changing Time Dynamically

const clock = createClock(
  document.getElementById('clock'),
  '10:00:00'
);

// Change the time without destroying the instance
clock.setTime('15:30:00');

Stopwatch

const stopwatch = createClock(
  document.getElementById('stopwatch'),
  undefined,
  { stopwatch: true }
);

// Control the stopwatch
stopwatch.stopClock();   // Pause
stopwatch.startClock();  // Resume
stopwatch.reset();       // Reset to 00:00:00

Stopwatch with Lap Times

const stopwatch = createClock(
  document.getElementById('stopwatch'),
  undefined,
  {
    stopwatch: true,
    lap: true,
    lapWord: 'Split'  // Optional: customize the lap word
  }
);

// Record a lap
const lap1 = stopwatch.lap();  // "Split 1: 00:00:15"
const lap2 = stopwatch.lap();  // "Split 2: 00:00:32"

// Get all laps
const laps = stopwatch.getLaps();

// Clear laps
stopwatch.clearLaps();

⚙️ Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | showCenti | boolean | false | Display centiseconds | | countdown | boolean | false | Run as countdown timer | | callback | function | undefined | Called when countdown reaches zero | | showHour | boolean | true | Show hours in display | | showMinute | boolean | true | Show minutes in display | | use12Hour | boolean | false | Use 12-hour format with AM/PM | | timezone | string | undefined | IANA timezone name for DST-aware support (e.g., "America/New_York") | | timezoneOffset | number | undefined | Static timezone offset in hours from UTC (no DST handling) | | stopwatch | boolean | false | Run as stopwatch (counts up from 00:00:00) | | lap | boolean | false | Enable lap/split mode (requires stopwatch: true) | | lapMode | "splits" \| "laps" \| "both" | "both" | Lap recording mode: "splits" (cumulative), "laps" (delta), or "both" | | lapWord | string | "Split" in lapMode: "splits", otherwise "Lap" | Custom word before lap number (set to "" for no word) | | useAnimationFrame | boolean | false | Use requestAnimationFrame for smoother updates. Falls back to setTimeout when page is hidden. |

🎯 API Reference

createClock(element, initialTime?, options?): ClockInstance

Creates a new clock instance.

Parameters:

  • element (HTMLElement): DOM element to render the clock in
  • initialTime (string, optional): Time in "HH:MM:SS" or "HH:MM:SS:CC" format
  • options (ClockOptions, optional): Configuration options

Returns: ClockInstance

ClockInstance Methods

| Method | Returns | Description | |--------|---------|-------------| | getTime() | string | Get current time as formatted string | | stopClock() | void | Stop/pause the clock | | startClock() | void | Start/resume the clock | | toggleClock() | void | Toggle between running and stopped | | isRunning() | boolean | Check if clock is currently running | | setTime(timeString) | void | Set a new time without destroying the instance | | reset() | void | Reset to initial time and restart (great for countdowns!) | | lap() | string | Record a lap/split time (only in lap mode) | | getLaps() | string[] | Get all recorded lap/split times (only in lap mode) | | getSplitTimes() | string[] | Get all split times (cumulative; lapMode: "splits" or "both") | | getLapTimes() | string[] | Get all lap times (delta; lapMode: "laps" or "both") | | getLapRecords() | LapRecord[] | Get all lap records with full details (only in lap mode) | | clearLaps() | void | Clear all recorded lap/split times (only in lap mode) | | bestLap() | LapRecord \| null | Get the fastest lap record (lapMode: "laps" or "both") | | worstLap() | LapRecord \| null | Get the slowest lap record (lapMode: "laps" or "both") | | destroy() | void | Clean up and remove the clock |

🔧 Bundler Configuration

This library ships ESM and CommonJS builds. For TypeScript ESM projects, moduleResolution: "node" provides broad compatibility. If you're using a bundler, you may want to configure it:

Vite

Works out of the box - no configuration needed.

webpack

// webpack.config.js
module.exports = {
  resolve: {
    extensions: ['.js', '.ts'],
    conditionNames: ['import', 'default']
  }
};

esbuild

// esbuild.config.js
esbuild.build({
  bundle: true,
  format: 'esm',
  mainFields: ['module', 'main']
});

TypeScript

The library includes TypeScript declarations. For the best experience, ensure your tsconfig.json uses a compatible moduleResolution:

{
  "compilerOptions": {
    "moduleResolution": "node"  // or "node16", "nodenext", or "bundler"
  }
}

Note: If you use moduleResolution: "bundler" in your project, the library will still work correctly since it's compiled with moduleResolution: "node" for broad compatibility.

🐛 Bug Fixes from v0.8

Multi-Instance Bug (FIXED ✅)

In the original jQuery version, calling stopClock(), startClock(), toggleClock(), or getTime() only worked on the last clock instance created. This was due to closure scope issues.

New version: Each clock instance has its own independent state and methods that work correctly.

// This now works correctly!
const clock1 = createClock(el1, '10:00:00');
const clock2 = createClock(el2, '20:00:00');

clock1.stopClock();  // Only stops clock1
clock2.stopClock();  // Only stops clock2

Variable Scope Bug (FIXED ✅)

Fixed inconsistent variable naming (clockloop vs clockLoop) that could cause timer issues.

📄 License

MIT License - Copyright (c) Thiago Cavalcanti Pimenta

🙏 Credits

This is a modern rewrite of the original JS-Clock jQuery plugin.