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

@wiltech-labs/ngx-calendar

v1.0.3

Published

Shared Angular calendar — day/week/month views on FullCalendar, Material 3 styled, with a day panel and an event detail/edit side panel.

Readme

@wiltech-labs/ngx-calendar

Day, week and month calendar for Angular apps, built on FullCalendar 7 and styled from the app's Material 3 tokens (light and dark, no palette file).

  • Wide screens (≥ 1200px): event chips show time and title. Clicking a day (or "+N more") opens a side panel listing every event that day; in Day view it follows the visible day.
  • Narrower screens: the same day panel sits below the calendar.
  • Phones: chips show only the start time (month view draws colour bars). The selected day's events (today until the user picks another) are always listed below the calendar.
  • Event panel: clicking an event opens it in an ngx-modals side panel: date, time, zone and description. Edit swaps in an ngx-forms form; Save emits eventSave. The calendar never changes events itself; the owner of the data applies the change.
  • All-day events (leave, deadlines) span their days in month view and sit in an all-day row in day and week views; the row appears only when there is one. They open read-only.
  • Holidays (holidays) shade their day (the whole column in day and week views) and carry a chip, "Public holiday · Green Monday", ahead of the day's events; the day panel lists them first. They can't be opened; clicking one selects the day.

Install

npm install @wiltech-labs/ngx-calendar

Add FullCalendar's two stylesheets to the app's angular.json build.options.styles, before the app's own styles. The calendar maps the theme's colours to the app's --mat-sys-* tokens itself, so no palette stylesheet is needed:

"styles": [
  "@fullcalendar/angular/skeleton.css",
  "@fullcalendar/angular/themes/monarch/theme.css",
  "src/styles.scss"
]

Add @fullcalendar/angular as a direct dependency of the app, since angular.json references it.

Usage

import { Component, signal } from '@angular/core';
import { Calendar, type CalendarEvent, type CalendarView } from '@wiltech-labs/ngx-calendar';

@Component({
  selector: 'app-schedule',
  imports: [Calendar],
  template: `<ngx-calendar [events]="events()" [(view)]="view" (eventSave)="save($event)" />`,
})
export class ScheduleComponent {
  protected readonly view = signal<CalendarView>('week');
  protected readonly events = signal<CalendarEvent[]>([
    {
      id: '1',
      title: 'Design review',
      description: 'Walk through the onboarding flow.',
      startDateTime: '2026-10-01T09:00Z',
      endDateTime: '2026-10-01T10:30Z',
      config: { color: 'tertiary' },
    },
  ]);

  protected save(event: CalendarEvent): void {
    this.events.update((events) => events.map((e) => (e.id === event.id ? event : e)));
  }
}

Inputs and outputs

| Name | Type | Default | Notes | | ----------- | ---------------------------------- | --------------- | ----------------------------------------------------- | | events | CalendarEvent[] | [] | | | holidays | CalendarHoliday[] | [] | Public holidays and closure days. Since 1.0.3. | | view | 'day' \| 'week' \| 'month' model | 'month' | Two-way: [(view)]. | | timeZone | IANA zone | the user's zone | Events are UTC; they're shown in this zone. | | editable | boolean | true | Shows the panel's Edit action. | | firstDay | 0–6 | the locale's | 0 = Sunday. | | eventSave | output CalendarEvent | | The edited event, start/end as 'YYYY-MM-DDTHH:mmZ'. | | daySelect | output string | | The day the user picked, 'YYYY-MM-DD'. | | rangeChange | output CalendarRange | | { start, end } dates on screen (both included), on first render and after each move. Since 1.0.2. |

Events

interface CalendarEvent<TSource = unknown> {
  id: string;
  title: string;
  description: string;
  startDateTime: string; // UTC, 'YYYY-MM-DDTHH:mmZ'; all-day: first day, 'YYYY-MM-DD'
  endDateTime: string; // UTC, 'YYYY-MM-DDTHH:mmZ'; all-day: last day (included)
  allDay?: boolean; // whole days, shown on those dates whatever the timeZone (since 1.0.1)
  config?: CalendarEventConfig;
  source?: TSource; // the app's own object, carried through untouched
}

interface CalendarEventConfig {
  color?: 'primary' | 'secondary' | 'tertiary' | 'error' | 'neutral'; // M3 container pair
  backgroundColor?: string; // overrides; prefer a token, Eg 'var(--mat-sys-primary)'
  textColor?: string;
  className?: string;
  editable?: boolean; // false hides Edit for this event
}

All-day events

Set allDay: true and give dates instead of instants, both ends included:

{
  id: 'leave-42',
  title: 'Eleni: annual leave',
  description: '',
  startDateTime: '2026-11-02',
  endDateTime: '2026-11-06',
  allDay: true,
  config: { color: 'secondary' },
}

The mapper takes an allDay reader too: allDay: (leave) => true. All-day events have no time to edit, so their panel has no Edit action; the day list and panel show "All day" (NGX_CALENDAR_TEXT's optional allDay, which also labels the all-day row).

Holidays

Pass the items an API using wiltech-labs-holidays sends, as they are (date, name, category; other fields are ignored):

<ngx-calendar [events]="events()" [holidays]="store.publicHolidays()" />
interface CalendarHoliday {
  date: string; // 'YYYY-MM-DD'
  name: string;
  category?: string; // 'public' (default): "Public holiday"; anything else: "Holiday"
}

The labels are NGX_CALENDAR_TEXT's optional publicHoliday and holiday.

Loading events for what's on screen

Fetch by rangeChange when the events come from an API that answers a date range:

<ngx-calendar [events]="events()" (rangeChange)="store.load($event.start, $event.end)" />

Mapping the app's own data

CalendarEventMapper turns any list into CalendarEvents and keeps each original on source:

private readonly mapper = inject(CalendarEventMapper);

protected readonly events = computed(() =>
  this.mapper.map(this.store.bookings(), {
    id: (b) => b.id,
    title: (b) => b.customerName,
    description: (b) => b.notes,
    startDateTime: (b) => b.startsAt,
    endDateTime: (b) => b.endsAt,
    config: (b) => ({ color: b.confirmed ? 'primary' : 'tertiary' }),
  }),
);

Locale and text

NGX_CALENDAR_LOCALE (dates, weekday names, first day of the week; default: the browser's language) and NGX_CALENDAR_TEXT (every label; default English) are resolver tokens, the same pattern as ngx-dates' NGX_DATES_LOCALE. Wire them to ngx-translations to follow a language switch:

{
  provide: NGX_CALENDAR_LOCALE,
  useFactory: () => { const t = inject(TranslationsService); return () => t.locale(); },
}

Theming

The grid reads FullCalendar's monarch (Material 3) theme variables, which this package points at --mat-sys-* roles. Optional overrides: --ngx-calendar-background (grid surface) and --ngx-calendar-panel-background (day panel).

Status

1.0.2 (all-day events, rangeChange) is on npm; 1.0.3 (holidays) is built, not yet published. Consumed by apps/showcase (/calendar) and Crewly's "Who's away" page.

Publishing

cd packages/calendar
npm run build

ngx-forms and ngx-modals are file:../x/dist dependencies (see root CLAUDE.md's "Inter-package deps"); build them first, or use npm run build:packages from the repo root. npm run build's postbuild script rewrites them to real version ranges in dist/package.json automatically. Then:

cd dist
npm publish

Bump version in the source package.json before building.