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

@marianmeres/calendar-utils

v2.0.0

Published

[![JSR](https://jsr.io/badges/@marianmeres/calendar-utils)](https://jsr.io/@marianmeres/calendar-utils) [![NPM](https://img.shields.io/npm/v/@marianmeres/calendar-utils)](https://www.npmjs.com/package/@marianmeres/calendar-utils) [![License](https://img.s

Readme

@marianmeres/calendar-utils

JSR NPM License

Low-level, UI-agnostic TypeScript primitives for date pickers, range selectors, and calendar event displays. Built on Luxon for timezone correctness; Svelte-compatible reactive stores via @marianmeres/store.

Features

  • Pure grid functions — month / week grids without state
  • Reactive stores — date picker, date range, month view, week view, events
  • Day-indexed event store — O(events on day) lookup, atomic batch / replaceAll, bounded cost for pathological spans
  • Multi-day + all-day events with placement info for rendering
  • Overlap helpers — hour-precision conflict queries and column layout for side-by-side events
  • Strict validation — UTC/offset enforced for timed events; rejects ambiguous inputs
  • DST-safe — correct in zones whose day starts at 01:00 on the transition day
  • Regional weeks — any first day of the week and configurable weekend days

Installation

# Deno
deno add jsr:@marianmeres/calendar-utils

# npm
npm install @marianmeres/calendar-utils

Quick Start

import {
	type CalendarEvent,
	createCalendarEvents,
	createMonthView,
	getWeekdayHeaders,
	layoutOverlappingEvents,
} from "@marianmeres/calendar-utils";

// Month view with reactive grid
const view = createMonthView({ year: 2024, month: 1 }, { zone: "UTC" });
const headers = getWeekdayHeaders(1, "short"); // ["Mon", ..., "Sun"]

view.subscribe(({ grid, monthLabel }) => {
	// grid is DayCell[][] — render however you like
});

// Event store with day-indexed lookup
interface MyEvent extends CalendarEvent {
	title: string;
	color: string;
}

const events = createCalendarEvents<MyEvent>([], { zone: "UTC" });

events.add({
	id: "1",
	start: "2024-01-15T09:00:00Z", // timed events MUST include Z or ±HH:MM
	end: "2024-01-17T17:00:00Z",
	title: "Conference",
	color: "blue",
});

// O(events on day) day query — placement info included
const placements = events.getForDay("2024-01-16");
// [{ event, isStart: false, isEnd: false, dayIndex: 1, spanDays: 3 }]

// All-day events use date-only ISO and are zone-independent
events.add({
	id: "2",
	start: "2024-01-20",
	end: "2024-01-22",
	allDay: true,
	title: "Holiday",
	color: "red",
});

// Hour-precision conflict check (half-open window, touching does not count)
const busy = events.getOverlapping("2024-01-15T14:00:00Z", "2024-01-15T15:00:00Z");

// Side-by-side layout for overlapping events
const dayEvents = placements.map((p) => p.event);
const slots = layoutOverlappingEvents(dayEvents, { zone: "UTC" });
// → [{ event, column, columnCount, groupId }] — render with left = column / columnCount

Bulk operations (single subscriber notification)

events.replaceAll(serverEvents); // atomic — pre-validates, swap, one notify

events.batch(() => { // arbitrary sequence, one notify, rollback on throw
	events.removeMany(deletedIds);
	events.addMany(newEvents);
	events.updateEvent("foo", { title: "Renamed" });
});

API

See API.md for the complete reference. See AGENTS.md for the agent-oriented architecture and conventions guide.

Configuration

interface ZoneConfig {
	zone?: string; // IANA timezone, default "local"
}

interface GridConfig extends ZoneConfig {
	weekStartsOn?: Weekday; // 1 = Monday (default) … 7 = Sunday; any weekday allowed
	weekendDays?: Weekday[]; // default [6, 7]
}

interface LoggingConfig {
	debug?: boolean;
	logger?: Logger; // stores only — pure helpers never log
}

Input rules

Every date argument accepts a DateTime, a Date or an ISO string. A DateTime or Date is an instant and is converted into the configured zone; a bare ISO date is wall-clock in that zone.

Pure helpers and store constructors throw on unparseable input. Store mutators and navigation methods warn, leave the state untouched and return false; store queries warn and return an empty result.

Event format contract

| Shape | start / end | Meaning | | ----------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------- | | Timed (allDay false/absent) | ISO 8601 (YYYY-MM-DDTHH:mm…) with mandatory Z or ±HH[:MM] | Exact instants, bucketed into the display zone | | All-day (allDay: true) | YYYY-MM-DD or ISO with TZ designator (date portion as written used) | Zone-independent inclusive [startDate, endDate] |

Bare local-time strings (e.g. "2024-01-15T09:00:00") and time-only strings are rejected by validateEvent. Events are treated as immutable once added — use updateEvent to change them.

License

MIT