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

@alphinex/dates

v1.0.2

Published

Intl-based date/time engine + DatePicker, DateRangePicker, TimePicker, DateTimePicker and the shared month-grid cell engine. No date-fns/dayjs/luxon. See documentation/PRODUCT-RESEARCH-MASTER-PLAN.md §10.3 (Sprint 37).

Readme

@alphinex/dates

Date and time for the Alphinex platform: an Intl-based engine, a month-grid cell engine, and four pickers built on top of them.

No date-fns, no dayjs, no luxon. Everything here is native Date plus Intl, so adding a date field to your app adds no third-party date library to your bundle.

pnpm add @alphinex/dates

Requires a <ThemeProvider> above it (the grids read dir to mirror their arrow-key axis under RTL), the same as Slider and Tooltip.


Quick start

import { ThemeProvider } from "@alphinex/theme";
import { DatePicker } from "@alphinex/dates";
import { useState } from "react";

function InvoiceForm() {
  const [dueAt, setDueAt] = useState<Date | null>(null);

  return (
    <ThemeProvider>
      <DatePicker
        aria-label="Due date"
        value={dueAt}
        onChange={setDueAt}
        placeholder="Pick a date"
      />
    </ThemeProvider>
  );
}

Components

DatePicker

A text field that accepts a typed date and opens a calendar.

<DatePicker
  aria-label="Due date"
  value={dueAt}
  onChange={setDueAt}
  min={new Date()} // nothing in the past
  disabledDaysOfWeek={[0, 6]} // no weekends
  disabledDates={publicHolidays}
  showYearControls // adds « » year paging
  locale="en-GB"
/>

You can always type into it. The text is parsed in the locale's own field order, so 03/04/2025 is 3 April in en-GB and 4 March in en-US — read from Intl, not from a hardcoded table. Written months work too (Mar 20, 2024, 20 März 2024), which matters because the field displays a month-name format by default.

Unparseable text is reverted, not cleared: a typo can't destroy a date you had already chosen. Emptying the field clears the value.

| Key | Does | | -------- | ---------------------------------------------- | | ↓ | Open the calendar and move focus into the grid | | Enter | Commit what you typed | | Escape | Discard what you typed / close the calendar |

DateRangePicker

Two date fields sharing one two-month calendar.

const [stay, setStay] = useState({ start: null, end: null });

<DateRangePicker
  value={stay}
  onChange={setStay}
  startLabel="Check in"
  endLabel="Check out"
  min={new Date()}
/>;

Which end a calendar click sets follows the focused field: click into "Check out" and pick a day, and only the end moves. onChange fires twice per range — once with end: null while it is half-picked, then again with both ends — so a controlled parent always sees the true state. A range picked backwards is ordered rather than rejected.

TimePicker

A time field with stepped suggestions.

<TimePicker
  aria-label="Start time"
  value={startTime}
  onChange={setStartTime}
  minuteStep={15}
  minTime="08:00"
  maxTime="18:00"
/>

The list is a convenience, not a constraint — typing 14:37 is accepted even on a 15-minute list. Pass enforceBounds if minTime/maxTime should be hard limits. 2:30 pm, 14:30, 1430 and 930 all parse.

Changing the time never changes the date: the calendar day of the existing value is preserved.

DateTimePicker

One field for both, with a calendar and a time list in a single popup.

<DateTimePicker
  aria-label="Starts at"
  value={startsAt}
  onChange={setStartsAt}
  minuteStep={30}
  defaultTime="09:00" // given to a date picked before any time was chosen
/>

Choosing a day never disturbs the time and choosing a time never disturbs the day, so the two halves can be set in either order. The popup does not close by itself — use Done, Escape, or click away.

Calendar

The month grid the pickers are built from, usable standalone as an inline calendar.

// Single (default)
<Calendar value={date} onChange={setDate} />

// Multiple
<Calendar mode="multiple" value={dates} onChange={setDates} maxSelected={5} />

// Range, two months side by side
<Calendar mode="range" numberOfMonths={2} value={range} onChange={setRange} />

| Key | Does | | ----------------------------- | ------------------------------ | | ← → | ± one day (mirrored under RTL) | | ↑ ↓ | ± one week | | Home / End | First / last day of the week | | PageUp / PageDown | ± one month | | Shift + PageUp/PageDown | ± one year | | Enter / Space | Select the focused day |

Focus follows across month boundaries, paging the view when it needs to. Days blocked by disabledDates/disabledDaysOfWeek stay focusable so a screen reader announces why they can't be chosen; only min/max stop arrow movement.

Useful options: weekStartsOn (0 = Sunday, default 1 = Monday) · showOutsideDays · fixedWeeks (always six rows, so a popup doesn't resize while paging) · numberOfMonths · weekendDays · footer · today (inject a clock so tests don't depend on the day they run).


With @alphinex/forms

import {
  DatePickerField,
  DateRangePickerField,
  DateTimePickerField,
  TimePickerField,
} from "@alphinex/forms";

<Form form={form} onSubmit={save}>
  <DatePickerField name="dueAt" label="Due date" min={new Date()} />
  <TimePickerField name="reminderAt" label="Reminder" minuteStep={15} />
  <DateTimePickerField name="startsAt" label="Starts at" />
  <DateRangePickerField name="stay" label="Stay" />
</Form>;

Each field stores a Date (or a { start, end } pair for the range) and accepts ISO strings in defaultValues — a form hydrated from JSON works without any conversion on your side.


The engine

Every function below is exported and usable on its own, without rendering anything.

import { addMonths, toISODate, parseDateInput, buildMonthGrid } from "@alphinex/dates";

Arithmetic — addDays addWeeks addMonths addYears addHours addMinutes · startOfDay endOfDay startOfWeek endOfWeek startOfMonth endOfMonth startOfYear endOfYear · isSameDay isSameMonth isSameYear isToday isBeforeDay isAfterDay isWithinDayRange · differenceInDays daysInMonth clampDate withTime · createDate isValidDate

Formatting — formatDate formatTime formatDateTime formatMonthYear formatDayLabel · toISODate toISOTime toISODateTime · weekdayLabels weekdayFullLabels monthLabels

Parsing — parseDateInput parseTimeInput parseDateTimeInput parseISODate · coerceDate applyParsedTime getDateOrder

Grids — buildMonthGrid getMonthMatrix getYearRange moveFocusedDate · isDateDisabled isOutOfBounds

Two things worth knowing

toISODate reads the local calendar, not UTC. new Date(2024, 0, 5, 0, 30).toISOString() gives 2024-01-04 anywhere east of Greenwich — the single most common date bug in web apps. Use toISODate / toISODateTime to serialise, and coerceDate / parseISODate to read back.

addMonths clamps instead of overflowing. Native setMonth turns 31 January + 1 month into 2 March, which shows up as a picker appearing to skip February. Here it is 29 February (or the 28th in a non-leap year). addYears does the same.

addMonths(new Date(2024, 0, 31), 1); // 29 Feb 2024
addYears(new Date(2024, 1, 29), 1); // 28 Feb 2025

Custom calendars

buildMonthGrid is the same cell engine Calendar and @alphinex/calendar's month view use, so a bespoke calendar agrees with the pickers by construction:

const weeks = buildMonthGrid({
  month: new Date(),
  weekStartsOn: 1,
  range: { start, end },
  constraints: { min, max, disabledDates },
  fixedWeeks: true,
});
// weeks: DayCell[][] — each cell has date, key, dayOfMonth, isOutsideMonth,
// isToday, isSelected, isDisabled, isRangeStart, isRangeEnd, isInRange, isWeekend

Accessibility

  • Calendar is a WAI-ARIA grid with roving tabindex — one tab stop for the whole month.
  • The pickers follow the date-picker combobox pattern: the input is a combobox with aria-haspopup="dialog", the popup is a non-modal dialog that traps Tab and restores focus.
  • Trigger buttons are named after their field ("Open calendar for Due date"), so two date fields on one page are distinguishable.
  • Every component is asserted against axe-core in its own test suite.

License

UNLICENSED — internal to Alphinex Solutions.